如何从泛型类或方法的成员中获取T的类型

假设我在类或方法中有一个泛型成员,如下所示:

public class Foo<T>{public List<T> Bar { get; set; }    
public void Baz(){// get type of T}}

当我实例化类时,T变成了MyTypeObject1,因此类具有泛型列表属性:List<MyTypeObject1>。这同样适用于非泛型类中的泛型方法:

public class Foo{public void Bar<T>(){var baz = new List<T>();        
// get type of T}}

我想知道我的类的列表包含什么类型的对象。那么名为Bar的列表属性或局部变量baz包含什么类型的T

我不能做Bar[0].GetType(),因为列表可能包含零个元素。我该怎么做?

797975 次浏览

(注意:我假设你所知道的是objectIList或类似的,并且列表在运行时可以是任何类型)

如果你知道它是List<T>,那么:

Type type = abc.GetType().GetGenericArguments()[0];

另一种选择是查看索引器:

Type type = abc.GetType().GetProperty("Item").PropertyType;

使用新的TypeInfo:

using System.Reflection;// ...var type = abc.GetType().GetTypeInfo().GenericTypeArguments[0];

试试看

list.GetType().GetGenericArguments()

如果我理解正确,你的列表与容器类本身具有相同的类型参数。如果是这种情况,那么:

Type typeParameterType = typeof(T);

如果您幸运地将object作为类型参数,请参阅Marc的回答

类型:

type = list.AsEnumerable().SingleOrDefault().GetType();

考虑这个:

我用它以同样的方式导出20个类型化列表:

private void Generate<T>(){T item = (T)Activator.CreateInstance(typeof(T));
((T)item as DemomigrItemList).Initialize();
Type type = ((T)item as DemomigrItemList).AsEnumerable().FirstOrDefault().GetType();if (type == null)return;if (type != typeof(account)) // Account is listitem in List<account>{((T)item as DemomigrItemList).CreateCSV(type);}}

GetGenericArgument()方法必须在实例的Base Type上设置(其类是泛型类myClass<T>)。否则,它返回类型[0]。

示例:

Myclass<T> instance = new Myclass<T>();Type[] listTypes = typeof(instance).BaseType.GetGenericArguments();

下面的方法对我有用。其中myList是某种未知类型的列表。

IEnumerable myEnum = myList as IEnumerable;Type entryType = myEnum.AsQueryable().ElementType;

使用以下扩展方法,您可以在没有反射的情况下逃脱:

public static Type GetListType<T>(this List<T> _){return typeof(T);}

更一般的:

public static Type GetEnumeratedType<T>(this IEnumerable<T> _){return typeof(T);}

用法:

List<string>        list    = new List<string> { "a", "b", "c" };IEnumerable<string> strings = list;IEnumerable<object> objects = list;
Type listType    = list.GetListType();           // stringType stringsType = strings.GetEnumeratedType();  // stringType objectsType = objects.GetEnumeratedType();  // BEWARE: object

您可以通过以下方式从任何实现IENumable的集合类型中获取“T”的类型:

public static Type GetCollectionItemType(Type collectionType){var types = collectionType.GetInterfaces().Where(x => x.IsGenericType&& x.GetGenericTypeDefinition() == typeof(IEnumerable<>)).ToArray();// Only support collections that implement IEnumerable<T> once.return types.Length == 1 ? types[0].GetGenericArguments()[0] : null;}

请注意,它不支持两次实现IENumable的集合类型,例如。

public class WierdCustomType : IEnumerable<int>, IEnumerable<string> { ... }

我想你可以返回一个类型数组,如果你需要支持这个…

此外,如果您经常这样做(例如在循环中),您可能还希望缓存每个集合类型的结果。

我使用这个扩展方法来完成类似的事情:

public static string GetFriendlyTypeName(this Type t){var typeName = t.Name.StripStartingWith("`");var genericArgs = t.GetGenericArguments();if (genericArgs.Length > 0){typeName += "<";foreach (var genericArg in genericArgs){typeName += genericArg.GetFriendlyTypeName() + ", ";}typeName = typeName.TrimEnd(',', ' ') + ">";}return typeName;}
public static string StripStartingWith(this string s, string stripAfter){if (s == null){return null;}var indexOf = s.IndexOf(stripAfter, StringComparison.Ordinal);if (indexOf > -1){return s.Substring(0, indexOf);}return s;}

你这样使用它:

[TestMethod]public void GetFriendlyTypeName_ShouldHandleReallyComplexTypes(){typeof(Dictionary<string, Dictionary<string, object>>).GetFriendlyTypeName().ShouldEqual("Dictionary<String, Dictionary<String, Object>>");}

这不是你想要的,但它有助于展示所涉及的技术。

public bool IsCollection<T>(T value){var valueType = value.GetType();return valueType.IsArray() || typeof(IEnumerable<object>).IsAssignableFrom(valueType) || typeof(IEnumerable<T>).IsAssignableFrom(valuetype);}

如果您不需要整个Type变量,只想检查类型,您可以轻松创建一个临时变量并使用is运算符。

T checkType = default(T);
if (checkType is MyClass){}

使用3dGrabber的解决方案

public static T GetEnumeratedType<T>(this IEnumerable<T> _){return default(T);}
//and now
var list = new Dictionary<string, int>();var stronglyTypedVar = list.GetEnumeratedType();

如果您想知道属性的基础类型,请尝试以下操作:

propInfo.PropertyType.UnderlyingSystemType.GenericTypeArguments[0]

您可以将此用于泛型列表的返回类型:

public string ListType<T>(T value){var valueType = value.GetType().GenericTypeArguments[0].FullName;return valueType;}

我是这样做的:

internal static Type GetElementType(this Type type){// Use type.GenericTypeArguments if it existsif (type.GenericTypeArguments.Any())return type.GenericTypeArguments.First();
return type.GetRuntimeProperty("Item").PropertyType);}

然后这样称呼它:

var item = Activator.CreateInstance(iListType.GetElementType());

var item = Activator.CreateInstance(Bar.GetType().GetElementType());

试试这个。

if(typeof(T)==typeof(Person))