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

Pat*_*ins 647 .net c# generics

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

public class Foo<T>
{
    public List<T> Bar { get; set; }

    public void Baz()
    {
        // get type of T
    }   
}
Run Code Online (Sandbox Code Playgroud)

当我实例化类时,T变为MyTypeObject1,所以类具有通用列表属性:List<MyTypeObject1>.这同样适用于非泛型类中的泛型方法:

public class Foo
{
    public void Bar<T>()
    {
        var baz = new List<T>();

        // get type of T
    }
}
Run Code Online (Sandbox Code Playgroud)

我想知道,我的类列表包含什么类型的对象.所以调用的list属性Bar或局部变量baz包含什么类型的T

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

Tam*_*ege 658

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

Type typeParameterType = typeof(T);
Run Code Online (Sandbox Code Playgroud)

如果您处于object作为类型参数的幸运情况,请参阅Marc的答案.

  • 我喜欢`typeof`的可读性.如果你想知道T的类型,只需使用`typeof(T)`:) (30认同)
  • @Reynevan当然你可以使用带有泛型参数的“typeof()”。你有什么不起作用的例子吗?或者您是否混淆了类型参数和引用? (7认同)
  • 哈哈 - 是的,非常真实; 我认为OP只有`object`,`IList`或类似的东西 - 但这很可能是正确的答案. (4认同)
  • 但是,您不能将 typeof() 与泛型参数一起使用。 (3认同)
  • 我实际上只是使用了typeof(Type)而且效果很好. (2认同)

Mar*_*ell 507

(注:我假设你知道objectIList或类似的,并且这个名单可以是任何类型的在运行时)

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

Type type = abc.GetType().GetGenericArguments()[0];
Run Code Online (Sandbox Code Playgroud)

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

Type type = abc.GetType().GetProperty("Item").PropertyType;
Run Code Online (Sandbox Code Playgroud)

使用新的TypeInfo:

using System.Reflection;
// ...
var type = abc.GetType().GetTypeInfo().GenericTypeArguments[0];
Run Code Online (Sandbox Code Playgroud)

  • @Daok:那么它不是List <T> (27认同)
  • 类型 type = abc.GetType().GetGenericArguments()[0]; ==&gt; 数组索引越界... (2认同)
  • 任何具有一种类型参数的通用都应该有效. (2认同)
  • 类型 type = abc.GetType().GetProperty("Item").PropertyType; 返回 BindingListView&lt;MyObject&gt; 而不是 MyObject... (2认同)

3dG*_*ber 48

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

public static Type GetListType<T>(this List<T> _)
{
    return typeof(T);
}
Run Code Online (Sandbox Code Playgroud)

或者更一般:

public static Type GetEnumeratedType<T>(this IEnumerable<T> _)
{
    return typeof(T);
}
Run Code Online (Sandbox Code Playgroud)

用法:

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
Run Code Online (Sandbox Code Playgroud)

  • 这只有在编译时已经知道`T`的类型时才有用.在这种情况下,您根本不需要任何代码. (9认同)
  • @recursive:如果您正在使用匿名类型的列表,这很有用。 (2认同)

Rau*_*otz 31

尝试

list.GetType().GetGenericArguments()
Run Code Online (Sandbox Code Playgroud)

  • new List <int>().GetType().GetGenericArguments()返回System.Type [1],其中System.Int32为条目 (7认同)

小智 14

这对我有用.myList是一些未知的列表.

IEnumerable myEnum = myList as IEnumerable;
Type entryType = myEnum.AsQueryable().ElementType;
Run Code Online (Sandbox Code Playgroud)


Seb*_*ebi 9

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

T checkType = default(T);

if (checkType is MyClass)
{}
Run Code Online (Sandbox Code Playgroud)

  • 这是完全错误的,相反,我们可以使用 ``` if (typeof(T) == typeof(Person)) ``` (5认同)

小智 9

您可以将此一个用于通用列表的返回类型:

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


小智 8

考虑一下:我使用它以相同的方式导出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);
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

GetGenericArgument()必须在实例的基本类型(其类是泛型类myClass<T>)上设置该方法.否则,它返回一个类型[0]

例:

Myclass<T> instance = new Myclass<T>();
Type[] listTypes = typeof(instance).BaseType.GetGenericArguments();
Run Code Online (Sandbox Code Playgroud)


Dan*_*olm 5

您可以使用以下方法从实现IEnumerable <T>的任何集合类型中获取“ 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;
}
Run Code Online (Sandbox Code Playgroud)

请注意,它不支持两次实现IEnumerable <T>的集合类型,例如

public class WierdCustomType : IEnumerable<int>, IEnumerable<string> { ... }
Run Code Online (Sandbox Code Playgroud)

我想如果您需要支持此类型,则可以返回一个类型数组。

另外,如果您经常这样做(例如循环执行),则可能还希望按集合类型缓存结果。


Ken*_*ith 5

我使用此扩展方法来完成类似的操作:

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;
}
Run Code Online (Sandbox Code Playgroud)

您可以这样使用它:

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

这并不是您要找的东西,但是对演示所涉及的技术很有帮助。