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.