How to get the type of T from a member of a generic class or method?
假设我在类或方法中有一个泛型成员,那么:
1 2 3 4 5 6 7 8 9 | public class Foo<T> { public List<T> Bar { get; set; } public void Baz() { // get type of T } } |
当我实例化类时,
1 2 3 4 5 6 7 8 9 |
我想知道我的类列表中包含的对象类型。那么名为
我不能执行
如果我理解正确,您的列表与容器类本身具有相同的类型参数。如果是这样,那么:
1 |
如果您有幸使用
(注:我假设您所知道的是
如果你知道它是一个
1 | Type type = abc.GetType().GetGenericArguments()[0]; |
另一种选择是查看索引器:
1 | Type type = abc.GetType().GetProperty("Item").PropertyType; |
使用新的类型信息:
1 2 3 | using System.Reflection; // ... var type = abc.GetType().GetTypeInfo().GenericTypeArguments[0]; |
通过以下扩展方法,您可以在不进行反射的情况下离开:
1 2 3 4 |
或更一般:
1 2 3 4 |
用途:
1 2 3 4 5 6 7 | List<string> list = new List<string> {"a","b","c" }; IEnumerable<string> strings = list; IEnumerable<object> objects = list; Type listType = list.GetListType(); // string Type stringsType = strings.GetEnumeratedType(); // string Type objectsType = objects.GetEnumeratedType(); // BEWARE: object |
尝试
1 | list.GetType().GetGenericArguments() |
这是我的工作。其中mylist是某种未知的列表。
1 2 | IEnumerable myEnum = myList as IEnumerable; Type entryType = myEnum.AsQueryable().ElementType; |
考虑一下:我用它以同样的方式导出20个类型列表:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 { ((T)item as DemomigrItemList).CreateCSV(type); } } |
如果您不需要整个类型变量,只想检查类型,您可以轻松创建一个临时变量,并使用is operator。
1 2 3 4 |
您可以将此类型用于泛型列表的返回类型:
1 2 3 4 5 | public string ListType<T>(T value) { var valueType = value.GetType().GenericTypeArguments[0].FullName; return valueType; } |
必须根据实例的基类型设置
例子:
1 2 |
我使用这个扩展方法来完成类似的事情:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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; } |
你这样使用它:
1 2 3 4 5 6 | [TestMethod] public void GetFriendlyTypeName_ShouldHandleReallyComplexTypes() { typeof(Dictionary<string, Dictionary<string, object>>).GetFriendlyTypeName() .ShouldEqual("Dictionary<String, Dictionary<String, Object>>"); } |
这不完全是你想要的,但它有助于展示所涉及的技术。
您可以从实现IEnumerable
1 2 3 4 5 6 7 8 9 | 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; } |
注意,它不支持实现IEnumerable
1 | public class WierdCustomType : IEnumerable<int>, IEnumerable<string> { ... } |
我想如果需要支持这一点,您可以返回一个类型数组…
此外,如果您经常这样做(例如在循环中),您可能还希望缓存每个集合类型的结果。
1 2 3 4 |
使用3Drabber的解决方案:
1 2 3 4 5 6 7 8 9 | public static T GetEnumeratedType<T>(this IEnumerable<T> _) { return default(T); } //and now var list = new Dictionary<string, int>(); var stronglyTypedVar = list.GetEnumeratedType(); |
对于那些试图直接处理类型名(例如使用switch语句)的开发人员,下面是一个示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | public static void TypeBasedLogic<T>(T item) { switch (typeof(T).ToString()) //e.g. System.Int32 { case nameof(System) +"." + nameof(Int32): //Logic for int Console.Write("It's an integer"); break; case nameof(System) +"." + nameof(Double): //Logic for double Console.Write("It's a double"); break; case nameof(System) +"." + nameof(Decimal): //Logic for decimal Console.Write("It's a decimal"); break; case nameof(System) +"." + nameof(String): //Logic for string Console.Write("It's a string"); break; default: //logic for the rest other System or custom types Console.Write("It's a"+ typeof(T).ToString()); break; } } |
用途:
1 | TypeBasedLogic(5); // outputs: It's an integer |
如果要了解属性的基础类型,请尝试以下操作:
1 | propInfo.PropertyType.UnderlyingSystemType.GenericTypeArguments[0] |
我就是这样做的
1 2 3 4 5 6 7 8 | internal static Type GetElementType(this Type type) { //use type.GenericTypeArguments if exist if (type.GenericTypeArguments.Any()) return type.GenericTypeArguments.First(); return type.GetRuntimeProperty("Item").PropertyType); } |
那就这样说吧
1 | var item = Activator.CreateInstance(iListType.GetElementType()); |
或
1 | var item = Activator.CreateInstance(Bar.GetType().GetElementType()); |
Type:
1 | type = list.AsEnumerable().SingleOrDefault().GetType(); |