2016-05-23 2 views
0

が渡された場合、IEnumerableのすべてのアイテムに対して最も一致する基本タイプを返すための組み込みメソッドがあり、nullable/non-nullable型と継承を処理します。 ?このような値セット間で共有タイプを見つける

何か:

var hs = new HashSet<object> {1,2,3,null}; 
Type t = GetSharedType(hs); //returns typeof(int?) 

hs = new HashSet<object> {new BaseClass(), new DerivedClass()}; 
t = GetSharedType(hs); //returns typeof(BaseClass) 

hs = new HashSet<object> {"1", 1}; 
t = GetSharedType(hs); //returns typeof(object) or null 

(私は私は自分を書くことができることを承知しています。内蔵のものがあるならば、私の質問です)。

+3

いいえありません。 –

+0

代わりに、コードをリファクタリングする必要があります。なぜあなたは知らない同じコレクションにオブジェクトを保存しますか? –

+0

@TimSchmelterそれは私のコレクションではありません。 (具体的には、DataGridのItemsSourceで、実行時に実行時に「述語」を一般的な方法で作成したいと思っています。) –

答えて

2

のようなものはありません、これを行うには組み込みのメカニズムはありません。いくつかを組み合わせることができますreflection APIs

まず、GetType()と、コレクション内の各オブジェクトのための本当の種類を取得することができます。

IEnumerable<Type> realTypes = hs.Select(o => o.GetType()); 

今、あなたはBaseType財産とGetInterfaces()方法を持っているTypeクラスのコレクションを持っています。 Ypuは、各タイプのすべての階層を取得するためにthis codeを使用することができます。

public static IEnumerable<Type> GetParentTypes(this Type type) 
{ 
    // is there any base type? 
    if ((type == null) || (type.BaseType == null)) 
    { 
     yield break; 
    } 

    // return all implemented or inherited interfaces 
    foreach (var i in type.GetInterfaces()) 
    { 
     yield return i; 
    } 

    // return all inherited types 
    var currentBaseType = type.BaseType; 
    while (currentBaseType != null) 
    { 
     yield return currentBaseType; 
     currentBaseType= currentBaseType.BaseType; 
    } 
} 

あなたは階層のコレクションを取得するためにそれを使用することができます:

IEnumerable<IEnumerable<Type>> baseTypes = realTypes.Select(t => t.GetParentTypes()); 

次のステップは、唯一の交差の値を持つように、すべてのこのリストをマージすることです。あなたはEnumerable.Intersect方法とthisコードでそれを行うことができます。

public static IEnumerable<T> IntersectAllIfEmpty<T>(params IEnumerable<T>[] lists) 
{ 
    IEnumerable<T> results = null; 

    lists = lists.Where(l => l.Any()).ToArray(); 

    if (lists.Length > 0) 
    { 
     results = lists[0]; 

     for (int i = 1; i < lists.Length; i++) 
      results = results.Intersect(lists[i]); 
    } 
    else 
    { 
     results = new T[0]; 
    } 

    return results; 
} 

は最後に、我々は持っている:

IEnumerable<Type> realTypes = hs.Select(o => o.GetType()); 
IEnumerable<IEnumerable<Type>> baseTypes = realTypes.Select(t => t.GetParentTypes()); 
IEnumerable<Type> inersectedBaseTypes = IntersectAllIfEmpty(baseTypes); 

その後、我々は、各タイプを反復し、それらの1つを確実にするためにType.IsAssignableFrom()メソッドを使用することができます

Type mostConcreteType = inersectedBaseTypes.Where(t => inersectedBaseTypes.Count(bt => t.IsAssignableFrom(bt)) == 1).FirstOrDefault(); 
-1

いいえには、これを行うための組み込み型はありません。あなた自身であなた自身で書かなければならないことが分かったので。

public static Type GetEnumerableType<T>(this IEnumerable<T> enumerable) 
{ 
    return typeof(T); 
} 
+1

'T == object'の場合、すべての項目が' int'または 'null'であっても' object'を返します。 –

+0

あなたの例は質問には関係ありません。私は明確に編集しました。 –

関連する問題