2011-02-23 4 views
3

私はあなたがLinqPadで得た素晴らしいことに触発されてデバッグのための非常に初歩的な汎用オブジェクトプリンタを作ろうとしています。オブジェクトがILookup <,>であるかどうかを検出して印刷するにはどうすればよいですか?

以下は、私の印刷機能の疑似コードです。私のreflection-fooは今のところ弱いですし、オブジェクトがILookupの場合に対処するのに苦労しています。関連するコレクションとともに各キーを表示してルックアップを列挙したいと思います。

ILookupは非ジェネリックインターフェイスを持たず、IDictionaryも実装していないので、現時点では固執しています。o as ILookup<object,object>と言うことはできません。任意の一般的なインターフェースを調べる方法を知りたいのですが... CustomObject<,,>の特別なケースがあるとします。

void Print(object o) 
{ 
    if(o == null || o.GetType().IsValueType || o is string) 
    { 
     Console.WriteLine(o ?? "*nil*"); 
     return; 
    } 

    var dict = o as IDictionary;  
    if(dict != null) 
    { 
     foreach(var key in (o as IDictionary).Keys) 
     { 
      var value = dict[key]; 
      Print(key + " " + value); 
     } 
     return; 
    } 

    //how can i make it work with an ILookup? 
    //????????? 


    var coll = o as IEnumerable; 
    if(coll != null) 
    { 
     foreach(var item in coll) 
     { print(item); } 
     return; 
    } 

    //else it's some object, reflect the properties+values 
    { 
     //reflectiony stuff 
    } 
} 
+0

、すなわち、 '無効印刷(IDictionaryをdictを)'、 '無効印刷(IEnumerableをienum)'、 '無効印刷(オブジェクトo)'など – mellamokb

+0

@mellamokb - Iそう思った。たぶん私は間違っていますが、相互に再帰的な 'Print'呼び出しは期待通りに動作しません。 – Kobi

+0

@ xanatosによると、 'ILookup'は' IEnumerable'の 'IEnumerable'です。あなたの現在のコードはそのまま動作するはずです。 'ILookup'型のオブジェクトを渡すとどうなりますか? – mellamokb

答えて

4

私はあなたがこのようにリフレクションを使用することができ、あなたは正確に達成しようとしているかわからないんだけど、あなたの特定の質問に答えるために:私は、このような方法でそれを書くことを試みた

public static void PrintIfLookup(object obj) 
{ 
    if (obj == null) 
     throw new ArgumentNullException("obj"); 

    // Find first implemented interface that is a constructed version of 
    // ILookup<,>, or null if no such interface exists. 
    var lookupType = obj 
        .GetType() 
        .GetInterfaces() 
        .FirstOrDefault 
        (i => i.IsGenericType && 
          i.GetGenericTypeDefinition() == typeof(ILookup<,>)); 

    if (lookupType != null) 
    { 
     // It is an ILookup<,>. Invoke the PrintLookup method 
     // with the correct type-arguments. 

     // Method to invoke is private and static. 
     var flags = BindingFlags.NonPublic | BindingFlags.Static; 

     // Assuming the containing type is called Foo. 
     typeof(Foo).GetMethod("PrintLookup", flags) 
        .MakeGenericMethod(lookupType.GetGenericArguments()) 
        .Invoke(null, new[] { obj }); 
    } 

} 

private static void PrintLookup<TKey, TElement>(ILookup<TKey, TElement> lookup) 
{ 
    // TODO: Printing logic  
} 

ジェネリックで強く型付けされた方法で印刷ロジックを書くことができます。必要に応じて、照会の各IGrouping<,>からキーと値を取得するために、より多くのリフレクションを行うことができます。

EDIT:あなたはC#4である場合はところで、あなたがif文の体全体を置き換えることができます。

PrintLookup((dynamic)obj); 
+0

素敵な、ちょうど私が欲しかった! – dan

0

型はリフレクションを使用して、いくつかの一般的なインターフェイスを実装することを決定するために:

var objType = o.GetType(); 

// get the ILookup<,> interface type (if the type implements it) 
var lookupInterface = objType.GetInterface("System.Linq.ILookup`2"); 

// the type implemented the interface if returned non-null value 
var isILookup = lookupInterface != null; 

ジェネリックタイプのマングリング名のパターンは、汎用の特定例えば

type_name`generic_parameter_count 

ありますタイプ:

type_name`generic_parameter_count[type_name_1,...,type_name_n] 
私たちは型パラメータを指定する必要はありませんので、

System.Linq.ILookup`2 

私たちは、正確なインスタンスでは興味がない:それはですので、この場合は

は、ILookup<,>は、2つのパラメータを持っていました。

+0

そのような文字列を使用することはお勧めできません。 – Ani

+0

@Ani:誰もが同じことを考えていますが、よりよい解決策はありますか? – mellamokb

+0

@mellamokb:はい、あります。そのトリックは、生成されたジェネリック型に対して 'GetGenericTypeDefinition'を呼び出すことです。 – Ani

1

多型は、あなたのコードを少し簡単にするかもしれません。これはまた、多型を有する方が簡単な場合があります

void Print(IDictionary dict) 
{ 
    foreach (var key in dict.Keys) 
    { 
     var value = dict[key]; 
     Print(key + " " + value); 
    } 
} 

void Print(object o) 
{ 
    if (o == null || o.GetType().IsValueType || o is string) 
    { 
     Console.WriteLine(o ?? "*nil*"); 
     return; 
    } 
} 

void Print(string s) 
{ 
    Console.WriteLine(s); 
} 

void Print(IEnumerable ie) 
{ 
    foreach (dynamic obj in ie) 
    { 
     Print(obj); 
    } 
} 
+0

それはまた私の問題だった、あなたは正直言って、私は避けたいと思う '動的'を使用する必要があります。アセンブリ、 'IDictionary'キー/値、' ILookup'などで動的フォーマットを使用したいとします。 – Kobi

+0

@Kobi:実際に 'dynamic'とreflectionの違いはありますか?彼らは両方ともタイプチェックをランタイムに移し、「動的」はこのような特定のアプリケーションを表現するためにより簡潔になります。 – mellamokb

+0

あなたは正しいです、ここでは「ダイナミック」がはるかに優れています。具体的には、型に 'if'を取り除き、多くの' as'/'is'を気にしません。私はまったく反射がないことを望んでいました。 – Kobi

関連する問題