リフレクションを介してIEnumerable<T>
からT
型を取得する方法はありますか?
例えば.
変数IEnumerable<Child>
infoがあります。リフレクションを介して子供のタイプを取得したい
_IEnumerable<T> myEnumerable;
Type type = myEnumerable.GetType().GetGenericArguments()[0];
_
したがって、
_IEnumerable<string> strings = new List<string>();
Console.WriteLine(strings.GetType().GetGenericArguments()[0]);
_
_System.String
_を出力します。
_Type.GetGenericArguments
_については、 [〜#〜] msdn [〜#〜] を参照してください。
編集:これはコメントの懸念に対処すると信じています:
_// returns an enumeration of T where o : IEnumerable<T>
public IEnumerable<Type> GetGenericIEnumerables(object o) {
return o.GetType()
.GetInterfaces()
.Where(t => t.IsGenericType
&& t.GetGenericTypeDefinition() == typeof(IEnumerable<>))
.Select(t => t.GetGenericArguments()[0]);
}
_
一部のオブジェクトは複数の汎用IEnumerable
を実装しているため、それらの列挙を返す必要があります。
Edit:言わなければならないが、クラスが複数のT
に対して_IEnumerable<T>
_を実装するのはひどい考えだ。
拡張メソッドを作成するだけです。これは私が投げたすべてのものでうまくいきました。
public static Type GetItemType<T>(this IEnumerable<T> enumerable)
{
return typeof(T);
}
同様の問題がありました。選択した回答は、実際のインスタンスに対して機能します。私の場合、タイプは(PropertyInfo
から)のみでした。
タイプ自体が_IEnumerable<T>
_の実装ではなくtypeof(IEnumerable<T>)
である場合、選択した回答は失敗します。
この場合、次のように機能します。
_public static Type GetAnyElementType(Type type)
{
// Type is Array
// short-circuit if you expect lots of arrays
if (type.IsArray)
return type.GetElementType();
// type is IEnumerable<T>;
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof (IEnumerable<>))
return type.GetGenericArguments()[0];
// type implements/extends IEnumerable<T>;
var enumType = type.GetInterfaces()
.Where(t => t.IsGenericType &&
t.GetGenericTypeDefinition() == typeof(IEnumerable<>))
.Select(t => t.GenericTypeArguments[0]).FirstOrDefault();
return enumType ?? type;
}
_
_IEnumerable<T>
_(ジェネリックを介して)がわかっている場合は、typeof(T)
だけが機能するはずです。それ以外の場合(object
、または非汎用IEnumerable
の場合)、実装されているインターフェイスを確認します。
_ object obj = new string[] { "abc", "def" };
Type type = null;
foreach (Type iType in obj.GetType().GetInterfaces())
{
if (iType.IsGenericType && iType.GetGenericTypeDefinition()
== typeof(IEnumerable<>))
{
type = iType.GetGenericArguments()[0];
break;
}
}
if (type != null) Console.WriteLine(type);
_
議論していただきありがとうございます。私は、以下のソリューションの基礎としてそれを使用しました。これは、私にとって関心のあるすべてのケース(IEnumerable、派生クラスなど)でうまく機能します。誰かがそれを必要とする場合に備えて、ここで共有すべきだと思った:
Type GetItemType(object someCollection)
{
var type = someCollection.GetType();
var ienum = type.GetInterface(typeof(IEnumerable<>).Name);
return ienum != null
? ienum.GetGenericArguments()[0]
: null;
}
単にtypeof(T)
を使用してください
EDIT:または、Tがない場合は、インスタンス化されたオブジェクトで.GetType()。GetGenericParameter()を使用します。
_IEnumerable<T>
_またはT
になる単純な状況の代替-GetGenericArguments()
の代わりにGenericTypeArguments
を使用することに注意してください。
_Type inputType = o.GetType();
Type genericType;
if ((inputType.Name.StartsWith("IEnumerable"))
&& ((genericType = inputType.GenericTypeArguments.FirstOrDefault()) != null)) {
return genericType;
} else {
return inputType;
}
_
これは、IEnumerable<>
タイプが継承ツリーの任意のレベルにある場合にも機能するという点で、Eli Algrantiのソリューションの改善点です。
このソリューションは、任意のType
から要素タイプを取得します。タイプがIEnumerable<>
でない場合、渡されたタイプを返します。オブジェクトの場合は、GetType
を使用します。型については、typeof
を使用し、結果に対してこの拡張メソッドを呼び出します。
public static Type GetGenericElementType(this Type type)
{
// Short-circuit for Array types
if (typeof(Array).IsAssignableFrom(type))
{
return type.GetElementType();
}
while (true)
{
// Type is IEnumerable<T>
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
return type.GetGenericArguments().First();
}
// Type implements/extends IEnumerable<T>
Type elementType = (from subType in type.GetInterfaces()
let retType = subType.GetGenericElementType()
where retType != subType
select retType).FirstOrDefault();
if (elementType != null)
{
return elementType;
}
if (type.BaseType == null)
{
return type;
}
type = type.BaseType;
}
}
私はこれが少し古いことを知っていますが、この方法はコメントで述べられたすべての問題と課題をカバーすると信じています。私の仕事に刺激を与えてくれたEli Algrantiに感謝します。
/// <summary>Finds the type of the element of a type. Returns null if this type does not enumerate.</summary>
/// <param name="type">The type to check.</param>
/// <returns>The element type, if found; otherwise, <see langword="null"/>.</returns>
public static Type FindElementType(this Type type)
{
if (type.IsArray)
return type.GetElementType();
// type is IEnumerable<T>;
if (ImplIEnumT(type))
return type.GetGenericArguments().First();
// type implements/extends IEnumerable<T>;
var enumType = type.GetInterfaces().Where(ImplIEnumT).Select(t => t.GetGenericArguments().First()).FirstOrDefault();
if (enumType != null)
return enumType;
// type is IEnumerable
if (IsIEnum(type) || type.GetInterfaces().Any(IsIEnum))
return typeof(object);
return null;
bool IsIEnum(Type t) => t == typeof(System.Collections.IEnumerable);
bool ImplIEnumT(Type t) => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>);
}
typeof(IEnumerable<Foo>)
. GetGenericArguments()
_[0]
_は最初の汎用引数を返します-この場合はtypeof(Foo)
。
これが私の読めないLinqクエリ式バージョンです。
public static Type GetEnumerableType(this Type t) {
return !typeof(IEnumerable).IsAssignableFrom(t) ? null : (
from it in (new[] { t }).Concat(t.GetInterfaces())
where it.IsGenericType
where typeof(IEnumerable<>)==it.GetGenericTypeDefinition()
from x in it.GetGenericArguments() // x represents the unknown
let b = it.IsConstructedGenericType // b stand for boolean
select b ? x : x.BaseType).FirstOrDefault()??typeof(object);
}
メソッドは非ジェネリックIEnumerable
も考慮に入れることに注意してください。具体的なインスタンスではなくobject
を引数として取るため、この場合はType
を返します。ちなみに、xは不明を表しているため、 このビデオ 意味がありませんが、関係ありません..
public static Type GetInnerGenericType(this Type type)
{
// Attempt to get the inner generic type
Type innerType = type.GetGenericArguments().FirstOrDefault();
// Recursively call this function until no inner type is found
return innerType is null ? type : innerType.GetInnerGenericType();
}
これは再帰関数であり、内部ジェネリック型のない具体的なタイプ定義を取得するまで、ジェネリック型のリストを最初に調べます。
このタイプでこのメソッドをテストしました:ICollection<IEnumerable<ICollection<ICollection<IEnumerable<IList<ICollection<IEnumerable<IActionResult>>>>>>>>
IActionResult
を返すはずです
これは私が通常行う方法です(拡張方法を介して):
public static Type GetIEnumerableUnderlyingType<T>(this T iEnumerable)
{
return typeof(T).GetTypeInfo().GetGenericArguments()[(typeof(T)).GetTypeInfo().GetGenericArguments().Length - 1];
}