简体   繁体   中英

.net generic method VB.Net vs C#, since when vb is more flexible?

Have a generic function, it doesn't really mater what it is doing (FYI coping one list of object to another), main idea is that it has two types Ts and 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;
    }

Have two simple classes

 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; }
}

My problem is that following code throw compilation error

 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... 
    }

And at the same time in VB.Net everything is ok!!!!

        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)()

My problem is I don't want to use dynamic everywhere because it will require extra coding plus it is run-time compilation.

What I am doing wrong in C#? please help.

The compiler message is quite clear about the problem: You need to specify both type arguments. If you specify only one, it is unclear which of both parameters it should be.

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

And this:

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

does not need to be dynamic. var is more appropriate here and will give you compile-time errors. If you do this, you get the same error for qD :

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

Otherwise, you will get the error only at runtime.

What I am doing wrong in C#?

The compiler won't partially infer generic parameters. Using dynamic defers that check to runtime, where it will likely fail. You need to supply both the input and output generic parameters in your call to CreateAndFillList .

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM