如何通过向构造函数提供System.Type值来在运行时实例化List<Foo>
或List<Bar>
?这个问题必须多次回答,但我找不到。
最终,我想制作一个像这样的扩展方法:
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>;
}
答案 0 :(得分:8)
您可以使用反射和MakeGenericType
方法在运行时指定List<>
的参数。
var typeParam = typeof(Foo);
var listType = typeof(List<>).MakeGenericType(typeParam);
然后使用Activator
类
var list = Activator.CreateInstance(listType);
但是,如果你要做的只是将IEnumerable
变为IEnumerable<T>
,Linq已经有方法(Cast
和OfType
)来执行此操作:
IEnumerable untypedList = ...
var foos = untypedList.Cast<Foo>(); // May throw InvalidCastException
var bars = untypedList.OfType<Bar>();
答案 1 :(得分:0)
您的扩展方法已经是通用的。只需调用构造函数。
var list = new List<T>();
如果要将非通用IEnumerable转换为通用IEnumerable,则System.Linq中已有方法。
return list.Cast<T>();
答案 2 :(得分:0)
您无法在逻辑上使Type type
参数与< T >
泛型参数匹配。
扩展方法必须返回非泛型IEnumerable
。
有可能使这个语法IEnumerable
实际上成为可能
(在运行时)持有通用IEnumerable < That particular type >
但执行扩展方法的用户程序员必须
做出假设,检查和强迫演员。
请注意,如果沿着这条路走下去,最终可能会遇到InvalidCastException
并且用户程序员不知道事情:)。
这就是:
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;
}
}
以下是你如何使用它:
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;
答案 3 :(得分:0)
这可能会成功
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>;
}
但是,T
的{{1}}类型无法保证。查看type
的签名:
CreateEnumerable<T>
参数中没有public static IEnumerable<T> CreateEnumerable<T>(this IEnumerable list, Type type)
来推断调用哪个泛型方法,也就是说,当你想调用它时需要指定一个类型参数。我认为T
是多余的,而不是
T
请注意,我不知道您希望拥有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;
}
。