クラスまたはメソッドにジェネリックメンバがあるとしましょう。
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()
はできません。どうすればいいの?
私が正しく理解していれば、あなたのリストはコンテナクラス自体と同じ型パラメータを持ちます。この場合、次のようになります。
Type typeParameterType = typeof(T);
あなたがobject
を型パラメータとして持っているという幸運な状況にあるならば、 Marcの答え を見てください。
(注:私はあなたが知っているのはobject
かIList
かそれに類似したものであり、そして実行時にリストはどんな型でもあり得ると仮定します)
あなたがそれがList<T>
であることを知っているならば、それから:
Type type = abc.GetType().GetGenericArguments()[0];
もう1つの選択肢は、インデクサーを調べることです。
Type type = abc.GetType().GetProperty("Item").PropertyType;
新しいTypeInfoを使う:
using System.Reflection;
// ...
var type = abc.GetType().GetTypeInfo().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
試します
list.GetType().GetGenericArguments()
それは私のための仕事です。私のリストはどこか未知の種類のリストです。
IEnumerable myEnum = myList as IEnumerable;
Type entryType = myEnum.AsQueryable().ElementType;
これを考えてみましょう。私はこれを使って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);
}
}
Type変数全体を必要とせず、単に型をチェックしたい場合は、一時変数を簡単に作成してis演算子を使用できます。
T checkType = default(T);
if (checkType is MyClass)
{}
ジェネリックリストの戻り型にこれを使うことができます。
public string ListType<T>(T value)
{
var valueType = value.GetType().GenericTypeArguments[0].FullName;
return valueType;
}
GetGenericArgument()
メソッドは、インスタンスの基本型(そのクラスは汎用クラスmyClass<T>
)に設定する必要があります。それ以外の場合は、タイプ[0]を返します。
例:
Myclass<T> instance = new Myclass<T>();
Type[] listTypes = typeof(instance).BaseType.GetGenericArguments();
私はこの拡張メソッドを使って似たようなことを実現しています。
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>>");
}
これはあなたが探しているものではありませんが、関連するテクニックを実証するのに役立ちます。
次のようにして、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;
}
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();
public bool IsCollection<T>(T value){
var valueType = value.GetType();
return valueType.IsArray() || typeof(IEnumerable<object>).IsAssignableFrom(valueType) || typeof(IEnumerable<T>).IsAssignableFrom(valuetype);
}
これは私がやった方法です
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);
}
それから、このようにそれを呼ぶ
var item = Activator.CreateInstance(iListType.GetElementType());
OR
var item = Activator.CreateInstance(Bar.GetType().GetElementType());
プロパティの基本型を知りたい場合は、これを試してください。
propInfo.PropertyType.UnderlyingSystemType.GenericTypeArguments[0]
たとえばswitch文を使用するために、 文字通り 型の名前を付けようとしている開発者にとっては、これが例です。
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;
}
}
使用法:
TypeBasedLogic(5); // outputs: It's an integer