Reputation: 10063
I have the following code:
public static List<object[]> Serialise2D_Rec<T>(IEnumerable<T> data)
{
int numElts = 0;
foreach (var item in data)
numElts++;
Type t = typeof(T); // Get type pointer
PropertyInfo[] propList = t.GetProperties();
List<object[]> toret = new List<object[]>();
for (long propID = 0; propID < propList.Count(); ++propID)
{
var proptype = propList[propID].PropertyType;
if (proptype.IsPrimitive || proptype == typeof(Decimal) || proptype == typeof(String))
{
toret.Add(new object[numElts + 1]);
toret[toret.Count - 1][0] = propList[propID].Name;
int row = 1;
foreach (T item in data)
{
toret[toret.Count - 1][row] = propList[propID].GetValue(item, null);
row++;
}
}
else
{
var lst = (IList)Activator.CreateInstance((typeof(List<>).MakeGenericType(proptype)));
foreach (T item in data)
{
lst.Add(propList[propID].GetValue(item, null));
}
List<object[]> serialisedProp = Serialise2D_Rec(lst);
}
}
return toret;
}
However this line will fail with:
List<object[]> serialisedProp = Serialise2D_Rec(lst);
With the error:
****: error CS0411: The type arguments for method '****.****.Serialise2D_Rec<T>(System.Collections.Generic.IEnumerable<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
How can I specify the type in the recursion, it seems that the syntax for dynamic generic types is not that trivial.
Upvotes: 2
Views: 4047
Reputation: 6442
It doesn't seem like you can use generics in this case. The line fails because lst
is a non-generic IList
and it's passed as arguent to Serialise2D_Rec
, which requires an IEnumerable<T>
.
I suggest that you change your method not to be generic; it uses reflection anyway, it may not have a big impact.
Try this:
public static List<object[]> Serialise2D_Rec(IList data)
{
int numElts = 0;
foreach (var item in data)
numElts++;
if (data.Count == 0)
throw new Exception("Cannot handle empty lists.");
Type t = data[0].GetType(); // Get type pointer
PropertyInfo[] propList = t.GetProperties();
List<object[]> toret = new List<object[]>();
for (long propID = 0; propID < propList.Count(); ++propID)
{
var proptype = propList[propID].PropertyType;
if (proptype.IsPrimitive || proptype == typeof(Decimal) || proptype == typeof(String))
{
toret.Add(new object[numElts + 1]);
toret[toret.Count - 1][0] = propList[propID].Name;
int row = 1;
foreach (object item in data)
{
toret[toret.Count - 1][row] = propList[propID].GetValue(item, null);
row++;
}
}
else
{
var lst = (IList)Activator.CreateInstance((typeof(List<>).MakeGenericType(proptype)));
foreach (object item in data)
{
lst.Add(propList[propID].GetValue(item, null));
}
List<object[]> serialisedProp = Serialise2D_Rec(lst);
}
}
return toret;
}
Upvotes: 1
Reputation: 25810
Since your type is dynamic, you won't know the type of the generic parameter until run-time. For this reason, you must also treat the function as dynamic, because you won't know the "type" of the function's generic signature until run-time.
You must use reflection to call a generic function dynamically. See How do I use reflection to call a generic method?
Upvotes: 2
Reputation: 523
Try this:
// Get The Method by reflection
MethodInfo serializerInfo = typeof(Serializer).GetMethod("Serialise2D_Rec",
BindingFlags.Public | BindingFlags.Static);
//Make a Generic instance of the type you want
serializerInfo = serializerInfo.MakeGenericMethod(lst.GetType());
List<object[]> serialisedProp = serializerInfo.Invoke(null, new object[] {lst});
Instead of Serializer in the typeof()
put the class that hold your func Serialise2D_Rec
Upvotes: 1
Reputation: 4164
Yes, that's because lst
is of type object
.
You'll need to dynamically invoke the correct generic type of Serialise2D_Rec<T>()
Upvotes: 0
Reputation: 27962
I don't see a valid use case for generics in your case. Usage of generics assume you are able to statically identify the type on compile-time (or its ancestor, at least). Why don't you just accept the non-generic IEnumerable
? If you do need to supply some base type of items in data
, then supply it as a parameter:
public static List<object[]> Serialise2D_Rec(IEnumerable data, Type t)
{
…
for (…)
{
if (…)
{
}
else
{
…
List<object[]> serialisedProp = Serialise2D_Rec(lst, proptype);
}
}
}
Side note: use the extension method data.Count()
instead of foreach (var item in data) numElts++;
.
Upvotes: 4