How can I instantiate a List<Foo>
or List<Bar>
at runtime by providing the System.Type value to a constructor? This question has to be answered many times but I can't find it.
Ultimately, I want to make an extension method like so:
public static IEnumerable<T> CreateEnumerable<T>(this System.Collections.IEnumerable list, Type type){
var stuff = something;
// magic happens to stuff where stuff becomes an IEnumerable<T> and T is of type 'type'
return stuff as IEnumerable<T>;
}
You can specify the parameter of List<>
at runtime using reflection and the MakeGenericType
method.
var typeParam = typeof(Foo);
var listType = typeof(List<>).MakeGenericType(typeParam);
And then instantiate it using the Activator
class
var list = Activator.CreateInstance(listType);
However, if all you're trying to do is turn an IEnumerable
into an IEnumerable<T>
, Linq already has methods ( Cast
and OfType
) to do this:
IEnumerable untypedList = ...
var foos = untypedList.Cast<Foo>(); // May throw InvalidCastException
var bars = untypedList.OfType<Bar>();
Your extension method is already generic. Just call the constructor.
var list = new List<T>();
If you want to convert a nongeneric IEnumerable to a generic one, there are already methods for that in System.Linq.
return list.Cast<T>();
You can't logically make the Type type
parameter match the < T >
generic argument.
The extension method must return the non-generic IEnumerable
.
It is possible to make it so as that this syntactical IEnumerable
will in fact (at runtime) hold a generic IEnumerable < That particular type >
but the user programmer which executes your extension method must make an assumption, a check and a forced cast.
Beware that you might end up with InvalidCastException
if you go down this route and the user programmer isn't aware of things :).
Here it goes:
public static class SomeExtensions {
private static readonly MethodInfo methodDefOf_PrivateHelper = typeof(SomeExtensions)
.GetMethod("PrivateHelper",
BindingFlags.NonPublic | BindingFlags.Static,
Type.DefaultBinder,
new [] { typeof(System.Collections.IEnumerable) },
null);
private static IEnumerable<T> PrivateHelper<T>(System.Collections.IEnumerable @this){
foreach (var @object in @this)
yield return (T)@object; // right here is were you can get the cast exception
}
public static System.Collections.IEnumerable DynamicCast(
this System.Collections.IEnumerable @this,
Type elementType
) {
MethodInfo particularizedMethod = SomeExtensions.methodDefOf_PrivateHelper
.MakeGenericMethod(elementType);
object result = particularizedMethod.Invoke(null, new object[] { @this });
return result as System.Collections.IEnumerable;
}
}
And here's how you could use that:
object[] someObjects = new object[] { "one", "two", "three" };
IEnumerable implicitlyCastedToEnumerable = someObjects;
Type unknownType = (DateTime.Now.Hour > 14) ? typeof(string) : typeof(int);
IEnumerable apparentlyNothingHappenedHere
= implicitlyCastedToEnumerable.DynamicCast(unknownType);
// if it's not after 14:00, then an exception would've jumped over this line and
// straight out the exit bracket or into some catch clause
// it it's after 14:00, then the apparentlyNothingHappenedHere enumerable can do this:
IEnumerable<string> asStrings = (IEnumerable<string>)apparentlyNothingHappenedHere;
// whereas the earlier would've cause a cast exception at runtime
IEnumerable<string> notGoingToHappen = (IEnumerable<string>)implicitlyCastedToEnumerable;
This might do the trick
public static IEnumerable<T> CreateEnumerable<T>(this IEnumerable list, Type type) {
var stuff=something;
var temp=stuff;
stuff=Array.CreateInstance(type, count) as T[];
// copy elements to stuff
return stuff as IEnumerable<T>;
}
However, nothing is guaranteed that T
is of type type
. Look at the signature of CreateEnumerable<T>
:
public static IEnumerable<T> CreateEnumerable<T>(this IEnumerable list, Type type)
There is no T
from the argument to infer which generic method to invoke, that is, it's required to specify a type parameter when you wish to call it. I would think that T
is redundant, and rather
public static IEnumerable CreateEnumerable(this IEnumerable list, Type type) {
var stuff=something;
var temp=stuff;
stuff=Array.CreateInstance(type, count);
// copy elements to stuff
return stuff as IEnumerable;
}
Note that I have no idea of the count
you would like to have.
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.