c# - 継承 - ジェネリッククラスやメソッドのメンバーからTの型を取得する方法は?




c# 戻り値 型 動的 (11)

クラスまたはメソッドに汎用メンバがあるとしましょう。

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

    public void Baz()
    {
        // get type of T
    }   
}

クラスをインスタンス化すると、 TMyTypeObject1になり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()はリストにゼロ要素が含まれている可能性があるため、できません。 どうしたらいいですか?


"T"の型は、IEnumerable <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;
}

IEnumerable <T>を2回実装するコレクション型はサポートしていないことに注意してください。

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

あなたがこれをサポートする必要があれば、配列の型を返すことができると思います...

また、コレクションの種類ごとに結果をキャッシュすることもできます(ループなど)。


3dGrabberのソリューションを使用して:

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

//and now 

var list = new Dictionary<string, int>();
var stronglyTypedVar = list.GetEnumeratedType();

(注:私はあなたが知っているのはobjectまたはIListまたはそれに類似したもので、リストは実行時にどのような型でもよいと仮定しています)

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];

GetGenericArgument()メソッドは、インスタンスの基本型(そのクラスは汎用クラスmyClass<T> )に設定する必要があります。 それ以外の場合は、型[0]を返します。

例:

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

これを考えてみましょう:同じ方法で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);
    }
}

それが私の仕事です。 myListは、わからない種類のリストです。

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

プロパティの基になる型を知りたい場合は、次のようにしてください:

propInfo.PropertyType.UnderlyingSystemType.GenericTypeArguments[0]

次の拡張方法を使用すると、反射なしで逃げることができます。

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();           // string
Type stringsType = strings.GetEnumeratedType();  // string
Type objectsType = objects.GetEnumeratedType();  // BEWARE: object

私はこの拡張メソッドを使って同様のことを達成します:

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;
}

あなたは次のように使います:

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

これはあなたが探しているものではありませんが、関連する技法のデモンストレーションに役立ちます。


試す

list.GetType().GetGenericArguments()

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

これを汎用リストの再実行タイプに使用することができます。





generics