Reputation:
Consider, that I've the following method:
public T Resolve<T>()
{
var targetType = typeof(T);
if (targetType.IsGenericType
&& targetType.GetGenerictTypeDefinition() == typeof(IEnumerable<>))
{
List<object> collection = this.ResolveCollection(targetType);
return (T)(object)collection;
}
return (T)this.ResolveSingle(targetType);
}
Sample usage:
IEnumerable<IFoo> coll = myClass.Resolve<IEnumerable<IFoo>>();
It is obvious, that sample will throw exception of invalid cast, because of covariance - we cannot cast List<object>
into IEnumerable<IFoo>
despite collection
contains implementations of IFoo
only.
Is there any workaround for that problem when using reflection and non-generic methods? I don't want to change Resolve
signature so I don't have generic type of item to use LINQ Cast
.
Upvotes: 0
Views: 1199
Reputation: 62012
It is going to be ugly. You can also call the Linq method Enumerable.Cast<>
after "making" it, i.e. filling out the generic argument.
Here is an extension method:
public static TIEnumerable ToIEnumerable<TIEnumerable>(this IEnumerable<object> source)
{
var type = typeof(TIEnumerable);
if (!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(IEnumerable<>))
throw new ArgumentException("Wrong type arg: " + type, "TIEnumerable");
var methOpen = typeof(Enumerable).GetMethod("Cast");
var methConstructed = methOpen.MakeGenericMethod(type.GenericTypeArguments[0]);
return (TIEnumerable)methConstructed.Invoke(null, new object[] { source, });
}
(You could even extend the non-generic IEnumerable
since Cast<>
operates on that.)
Then the body of your if
(in your question) could be:
List<object> collection = this.ResolveCollection(targetType);
return collection.ToIEnumerable<T>();
If you want eager iteration and returning a List<>
, that is:
List<object> collection = this.ResolveCollection(targetType);
return collection.ToIEnumerable<T>()
.ToList();
Upvotes: 1
Reputation:
Found workaround:
List<object> collection = this.ResolveCollection(targetType);
var itemType = targetType.GetGenericArguments()[0];
var listType = typeof(List<>).MakeGenericType(itemType);
var listInstance = Activator.CreateInstance(listType, new object[0]) as IList;
foreach (var instance in collection)
{
listInstance.Add(instance);
}
return (T)listInstance;
Then, casting works like a chram.
Upvotes: 0