.net的通用方法VB.net与C#相比,因为当VB更灵活

本文关键字:VB net 因为 方法 相比 | 更新日期: 2023-09-27 18:20:20

有一个通用函数,它并不真正关心它在做什么(仅供参考,将一个对象列表对应到另一个对象),主要思想是它有两种类型Ts和Tp-

        public static List<Tp> CreateAndFillList<Ts, Tp>(this IEnumerable<Ts> sItems) where Tp : class, new()
    {
        Type myType = default(Type);
        PropertyInfo[] pSourceAllInfos = null;
        if (pSourceAllInfos == null)
        {
            myType = typeof(Ts);
            pSourceAllInfos = myType.GetProperties(BindingFlags.Public | BindingFlags.Instance).ToArray();
        }
        PropertyInfo[] pTargetAllInfos = null;
        if (pTargetAllInfos == null)
        {
            myType = typeof(Tp);
            pTargetAllInfos = myType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(pi => pi.CanWrite).ToArray();
        }
        var joinedPI = (from spi in pSourceAllInfos
                        join tpi in pTargetAllInfos on spi.Name.ToLower() equals tpi.Name.ToLower()
                        select new { spi, tpi }).ToList();
        List<Tp> retList = new List<Tp>();
        foreach (var sItem in sItems)
        {
            Tp tpNewItem = new Tp();
            foreach (var jpi in joinedPI)
            {
                jpi.tpi.SetValue(tpNewItem, jpi.spi.GetValue(sItem, null), null);
            }
            retList.Add(tpNewItem);
        }
        return retList;
    }

有两个简单的类

 public class SourceInfo
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string SourceData { get; set; }
}
public class TargetInfo
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string TargetData { get; set; }
}

我的问题是以下代码引发编译错误

 private void button1_Click(object sender, EventArgs e)
    {
        List<SourceInfo> srcLst = new List<SourceInfo>();
        srcLst.Add(new SourceInfo() { Id = 1, Name = "First", SourceData = "data1" });
        srcLst.Add(new SourceInfo() { Id = 2, Name = "Second", SourceData = "data2" });
        var q = from li in srcLst
                    select new { li.Id, li.Name };
        dynamic qD = from li in srcLst
                select new { li.Id, li.Name };
        var resultLst = srcLst.CreateAndFillList<TargetInfo>(); 
        //Using the generic method 'ExtensionTest.Extensions.CreateAndFillList<Ts,Tp>(System.Collections.Generic.IEnumerable<Ts>)' requires 2 type arguments
        var resultLst1 = q.CreateAndFillList<TargetInfo>(); 
        //Using the generic method 'ExtensionTest.Extensions.CreateAndFillList<Ts,Tp>(System.Collections.Generic.IEnumerable<Ts>)' requires 2 type arguments
        var resultLst2 = qD.CreateAndFillList<TargetInfo>();
        //works but will have to use dynamic... 
    }

同时在VB.Net中一切都很好!!!!

        Dim lst As List(Of SourceInfo) = New List(Of SourceInfo)()
    lst.Add(New SourceInfo() With {.Id = 1, .Name = "First"})
    lst.Add(New SourceInfo() With {.Id = 2, .Name = "Second"})
    Dim q = From li In lst
           Select New With {li.Id, li.Name}
    Dim retLst = lst.CreateAndFillList(Of TargetInfo)()
    Dim retLst1 = q.CreateAndFillList(Of TargetInfo)()

我的问题是,我不想在任何地方都使用动态,因为它需要额外的编码,而且是运行时编译。

我在C#中做错了什么?请帮忙。

.net的通用方法VB.net与C#相比,因为当VB更灵活

编译器消息非常清楚这个问题:您需要同时指定两个类型参数。如果你只指定一个,就不清楚它应该是两个参数中的哪一个

var resultLst = srcLst.CreateAndFillList<SourceInfo, TargetInfo>();
var resultLst1 = q.CreateAndFillList<SourceInfo, TargetInfo>();

这个:

dynamic qD = from li in srcLst
             select new { li.Id, li.Name };

不需要是动态的。var在这里更合适,它会给您带来编译时错误。如果你这样做,你会得到相同的错误qD:

var resultLst2 = qD.CreateAndFillList<SourceInfo, TargetInfo>();

否则,您将只在运行时得到错误。

我在C#中做错了什么?

编译器不会部分推断泛型参数。使用dynamic会将该检查推迟到运行时,在那里它很可能会失败。您需要在对CreateAndFillList的调用中提供输入和输出通用参数。

var resultLst = srcLst.CreateAndFillList<SourceInfo, TargetInfo>();