Как я могу определить, является ли объект ILookup <,> и распечатать его? - PullRequest
3 голосов
/ 23 февраля 2011

Я пытаюсь сделать очень простой универсальный объектный принтер для отладки, вдохновленный удивительностью, которую вы получаете в LinqPad.

Ниже приведен псевдокод для моей функции печати.Моя рефлексия на данный момент слаба, и я изо всех сил пытаюсь разобраться со случаем, когда объект представляет собой 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
    }
}

Ответы [ 3 ]

4 голосов
/ 23 февраля 2011

Я не уверен, что именно вы пытаетесь достичь, но чтобы ответить на ваш конкретный вопрос, вы можете использовать отражение следующим образом:

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<,> в поиске.

РЕДАКТИРОВАТЬ : Кстати, если вы находитесь на C # 4, вы можете заменить все тело оператора if на:

PrintLookup((dynamic)obj);
1 голос
/ 23 февраля 2011

Полиморфизм может сделать ваш код немного проще.

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 голосов
/ 23 февраля 2011

Чтобы определить, что тип реализует некоторый универсальный интерфейс, используя отражение:

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]

В этом случае ILookup<,> имеет два параметра, поэтому это:

System.Linq.ILookup`2

Нас не интересует точный экземпляр, поэтому нам не нужно указыватьпараметры типа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...