回答:
IEnumerable<T> myEnumerable;
Type type = myEnumerable.GetType().GetGenericArguments()[0];
したがって、
IEnumerable<string> strings = new List<string>();
Console.WriteLine(strings.GetType().GetGenericArguments()[0]);
プリントSystem.String
。
MSDN forを参照してくださいType.GetGenericArguments
。
編集:私はこれがコメントの懸念に対処すると信じています:
// 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
ているため、それらの列挙を返す必要があります。
編集:私は言わなければならないが、クラスがIEnumerable<T>
複数のために実装するのはひどい考えですT
。
拡張メソッドを作るだけです。これは、私が投げたすべてのもので機能しました。
public static Type GetItemType<T>(this IEnumerable<T> enumerable)
{
return typeof(T);
}
同様の問題がありました。選択した回答は実際のインスタンスで機能します。私の場合、タイプは(からPropertyInfo
)しかありませんでした。
タイプ自体がtypeof(IEnumerable<T>)
の実装ではない場合、選択した回答は失敗します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;
}
Type.GenericTypeArguments
-dotNet FrameWorkバージョン> = 4.5のみ。それ以外の場合- Type.GetGenericArguments
代わりに使用してください。
IEnumerable<T>
(ジェネリックを介して)を知っている場合typeof(T)
は、動作するはずです。それ以外の場合(object
、またはnon-generic 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);
Type type
パラメーターではなくパラメーターで使用しようとする人にとっての1つの小さな落とし穴object obj
:に置き換えobj.GetType()
ても何も得られないtype
ため、単に置き換えることはできませtypeof(IEnumerable<T>)
ん。これを回避type
するには、それ自体をテストして、それがIEnumerable<>
そのインターフェースの総称であるかどうかを確認します。
どうもありがとうございました。私はそれを以下のソリューションの基礎として使用しました。これは、関心のあるすべてのケース(IEnumerable、派生クラスなど)でうまく機能します。誰かもそれを必要とする場合に備えて、ここで共有するべきだと思いました:
Type GetItemType(object someCollection)
{
var type = someCollection.GetType();
var ienum = type.GetInterface(typeof(IEnumerable<>).Name);
return ienum != null
? ienum.GetGenericArguments()[0]
: null;
}
someCollection.GetType().GetInterface(typeof(IEnumerable<>).Name)?.GetGenericArguments()?.FirstOrDefault()
どちらかになるだろう単純な状況のための代替IEnumerable<T>
またはT
のノートを使用- GenericTypeArguments
の代わりにGetGenericArguments()
。
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<>);
}
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
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は未知数を表すので、無関係ですが、このビデオはおもしろいと思いました。