如何检测对象是否是 ILookup<,>并打印它?

发布于 2024-10-19 04:11:22 字数 1068 浏览 1 评论 0 原文

我正在尝试制作一个非常基本的通用对象打印机用于调试,受到 LinqPad 中令人惊叹的功能的启发。

下面是我的打印函数的伪代码。我的 Reflection-foo 目前有点弱,我正在努力处理对象是 ILookup 的情况,因为我想枚举查找,将每个键与其关联的集合一起打印。

ILookup 没有非通用接口,也没有实现 IDictionary,所以我现在有点卡住了,因为我不能说 o as ILookup ...就此而言,我想知道如何深入研究任何通用接口...假设我想要 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
    }
}

I'm trying to make a very rudimentary generic object printer for debugging, inspired by the awesomeness you get in LinqPad.

Below is the pseudocode for my print function. My reflection-foo is kind of weak at the moment and I'm struggling to deal with the case when the object is an ILookup, as I'd like enumerate the lookup, printing each key alongside its associated collection.

ILookup doesn't have a non-generic interface and it doesn't implement IDictionary, so I'm kind of stuck at the moment, as I can't say o as ILookup<object,object>... For that matter, I'd like to know how to delve into any generic interface...suppose I'd like to have a special case for 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
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

姜生凉生 2024-10-26 04:11:22

我不确定你想要确切地完成什么,但是为了回答你的具体问题,你可以使用这样的反射:

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);

I'm not sure what you're trying to accomplish exactly, but to answer your specific question, you can use reflection like this:

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    
}

I've tried to write it in such a way that you can write the printing logic in a strongly-typed manner with generics. If you prefer, you can instead do even more reflection to get the key and values out of each IGrouping<,> in the lookup.

EDIT: By the way, if you are on C# 4, you can replace the entire body of the if statement with:

PrintLookup((dynamic)obj);
傾旎 2024-10-26 04:11:22

多态性可能会让你的代码更简单一些。

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);
    }
}

Polymorphism might make your code a little simpler.

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);
    }
}
对你再特殊 2024-10-26 04:11:22

要确定该类型使用反射实现某些泛型接口:

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

我们对确切的实例不感兴趣,所以我们不需要指定类型参数。

To determine that the type implements some generic interface using reflection:

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;

The pattern for the name mangling for generic types is

type_name`generic_parameter_count

For a specific instance of a generic type:

type_name`generic_parameter_count[type_name_1,...,type_name_n]

In this case, ILookup<,> had two parameters so it's:

System.Linq.ILookup`2

We're not interested in the exact instance so we don't need to specify the type parameters.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文