8

重複の可能性:
IEnumerable<T>からタイプTを取得

私はのプロパティタイプを持っていますIEnumerable

public IEnumerable PossibleValues { get; set; }

インスタンス化された基本タイプをどのように見つけることができますか?

たとえば、次のように作成された場合:

PossibleValues = new int?[] { 1, 2 }

タイプが「int」であることを知りたい。

4

3 に答える 3

9
Type GetBaseTypeOfEnumerable(IEnumerable enumerable)
{
    if (enumerable == null)
    {
        //you'll have to decide what to do in this case
    }

    var genericEnumerableInterface = enumerable
        .GetType()
        .GetInterfaces()
        .FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>));

    if (genericEnumerableInterface == null)
    {
        //If we're in this block, the type implements IEnumerable, but not IEnumerable<T>;
        //you'll have to decide what to do here.

        //Justin Harvey's (now deleted) answer suggested enumerating the 
        //enumerable and examining the type of its elements; this 
        //is a good idea, but keep in mind that you might have a
        //mixed collection.
    }

    var elementType = genericEnumerableInterface.GetGenericArguments()[0];
    return elementType.IsGenericType && elementType.GetGenericTypeDefinition() == typeof(Nullable<>)
        ? elementType.GetGenericArguments()[0]
        : elementType;
}

この例にはいくつかの制限があり、アプリケーションに関係する場合と関係しない場合があります。タイプが実装する場合は処理しませんが、は処理しませIEnumerableIEnumerable<T>。タイプがIEnumerable<T>複数回実装する場合は、1つの実装を任意に選択します。

于 2012-10-04T13:39:58.280 に答える
3

可能な値のタイプが必要な場合は、これを行うことができます。

var type = PossibleValues.GetType().ToString(); // "System.Nullable`1[System.Int32][]"

または、PossibleValuesに含まれるアイテムのタイプが必要な場合は、これを行うことができます(配列が実際に質問で説明されている値を持っていると仮定します)。

var type = PossibleValues.Cast<object>().First().GetType().ToString(); // "System.Int32"



編集

配列にアイテムが含まれていない可能性がある場合は、もちろん、nullチェックを行う必要があります。

var firstItem = PossibleValues.Cast<object>().FirstOrDefault(o => o != null);
var type = string.Empty;
if (firstItem != null)
{
    type = firstItem.GetType().ToString();
}
于 2012-10-04T13:33:47.603 に答える
2

2つの既存のアプローチは、オブジェクトが実装されているIEnumerable<T>かどうかを確認するか、セットの最初のアイテムのタイプを確認することです。1つ目は、実際に実装されているオブジェクトに依存しIEnumerable<T>、2つ目は、シーケンス内のすべてのアイテムが同じ派生型である場合にのみ機能します。

興味深い質問の1つは、すべてのアイテムに共通するタイプ、またはすべてのアイテムに共通する最も狭いタイプは何かということです。

簡単なヘルパーメソッドから始めます。タイプを指定すると、そのタイプのシーケンスとそのすべての基本タイプが返されます。

public static IEnumerable<Type> getBaseTypes(Type type)
{
    yield return type;

    Type baseType = type.BaseType;
    while (baseType != null)
    {
        yield return baseType;
        baseType = baseType.BaseType;
    }
}

次に、最初にすべての最も派生したタイプを検索し、次にシーケンス内の各タイプのすべての基本タイプを取得し、最後にintersectそれらのアイテムのみを取得するために使用することにより、シーケンスのすべての一般的なタイプを取得するメソッドがあります。すべてに共通点があります:

public static IEnumerable<Type> getCommonTypes(IEnumerable source)
{
    HashSet<Type> types = new HashSet<Type>();
    foreach (object item in source)
    {
        types.Add(item.GetType());
    }

    return types.Select(t => getBaseTypes(t))
        .Aggregate((a, b) => a.Intersect(b));
}

最初のメソッドのタイプの順序は、最も派生したものから最も派生していないものへとIntersect並べられ、順序が維持されるため、結果のシーケンスは、最も派生したものから最も派生していないものの順になることに注意してください。これらすべてのタイプに共通する最も狭いタイプを見つけたい場合はFirst、このメソッドの結果を使用するだけです。(すべてがそこから派生するためobject、元のアイテムがない場合を除いて、ここには常に少なくとも1つのタイプが返されることに注意してくださいIEnumerable

于 2012-10-04T14:19:11.933 に答える