检测 IEnumerable 是否为是分组的,在检查类型时我得到了一些疯狂的结果

发布于 2025-01-02 12:53:01 字数 2511 浏览 1 评论 0 原文

所以我试图弄清楚传递给我的方法的一些随机 IEnumerable 是否已分组。我的想法是,我将以不同的方式处理分组数据。我的问题是 IGrouping<> 是一个通用接口,它没有实现非通用接口,并且出于某种原因我无法使用 is 对其进行测试声明。

为了测试这一点,这里是我的示例代码:

        var dict = new Dictionary<int, string>() {
            {1, "Prime" },
            {2, "Prime" },
            {3, "Prime" },
            {4, "Not" },
            {5, "Prime" },
            {6, "Not" },
            {7, "Prime" },
            {8, "Not" },
            {9, "Not" },
            {10, "Not" },
            {11, "Prime" }
        };
        var grouped = from d in dict
                      group d by d.Value into gd
                      select gd;
        Debug.WriteLine("IEnumerable<IGrouping<string, KeyValuePair<int, string>>>: {0}", grouped is IEnumerable<IGrouping<string, KeyValuePair<int, string>>>);
        Debug.WriteLine("IEnumerable<IGrouping<object, KeyValuePair<int, string>>>: {0}", grouped is IEnumerable<IGrouping<object, KeyValuePair<int, string>>>);
        Debug.WriteLine("IEnumerable<IGrouping<object, KeyValuePair<object, object>>: {0}", grouped is IEnumerable<IGrouping<object, object>>);
        Debug.WriteLine("IEnumerable<IGrouping<object, object>: {0}", grouped is IEnumerable<IGrouping<object, object>>);
        Debug.WriteLine("IEnumerable<object>: {0}", grouped is IEnumerable<object>);

输出如下:

IEnumerable<IGrouping<string, KeyValuePair<int, string>>>: True
IEnumerable<IGrouping<object, KeyValuePair<int, string>>>: True
IEnumerable<IGrouping<object, KeyValuePair<object, object>>: False
IEnumerable<IGrouping<object, object>: False
IEnumerable<object>: True

所以看来,除非我知道被分组的值的类型,否则我无法测试它是否被分组?这是 .Net Framework 中的错误吗?

上面的结果怎么可能呢?


编辑:Jon Skeet 的回答非常准确...出于对其他遇到与我同样困难的人的礼貌,以下代码完成了检查 IEnumerable 是否已分组的工作(基于脱离了 Skeet 先生使用动态关键字的奇特想法):

    public static bool IsGrouped (dynamic test) {
        return CheckGrouping(test);
    }
    static bool CheckGrouping(object o ) {
        return false;
    }
    static bool CheckGrouping<TKey, TValue>(IEnumerable<IGrouping<TKey, TValue>> grouping) {
        return true;
    }

假设代码与上面相同:

IsGrouped(dict); //false
IsGrouped(grouped); //true

So I'm trying to figure out if some any random IEnumerable passed to my method has been grouped. The idea being that I'm going to handle grouped data differently. My problem is the IGrouping<> is a generic interface that doesn't implement a non-generic interface, and for whatever reason I can't test for it with is statements.

To test this out here is my sample code:

        var dict = new Dictionary<int, string>() {
            {1, "Prime" },
            {2, "Prime" },
            {3, "Prime" },
            {4, "Not" },
            {5, "Prime" },
            {6, "Not" },
            {7, "Prime" },
            {8, "Not" },
            {9, "Not" },
            {10, "Not" },
            {11, "Prime" }
        };
        var grouped = from d in dict
                      group d by d.Value into gd
                      select gd;
        Debug.WriteLine("IEnumerable<IGrouping<string, KeyValuePair<int, string>>>: {0}", grouped is IEnumerable<IGrouping<string, KeyValuePair<int, string>>>);
        Debug.WriteLine("IEnumerable<IGrouping<object, KeyValuePair<int, string>>>: {0}", grouped is IEnumerable<IGrouping<object, KeyValuePair<int, string>>>);
        Debug.WriteLine("IEnumerable<IGrouping<object, KeyValuePair<object, object>>: {0}", grouped is IEnumerable<IGrouping<object, object>>);
        Debug.WriteLine("IEnumerable<IGrouping<object, object>: {0}", grouped is IEnumerable<IGrouping<object, object>>);
        Debug.WriteLine("IEnumerable<object>: {0}", grouped is IEnumerable<object>);

Output is as follows:

IEnumerable<IGrouping<string, KeyValuePair<int, string>>>: True
IEnumerable<IGrouping<object, KeyValuePair<int, string>>>: True
IEnumerable<IGrouping<object, KeyValuePair<object, object>>: False
IEnumerable<IGrouping<object, object>: False
IEnumerable<object>: True

So it seems that unless I know the type of the values being grouped, I can't test to see if it's grouped? Is this a bug in the .Net Framework?

How are the results above even possible?


EDIT: Jon Skeet's answer was dead on... As a courtesy to anyone else that find themselves here with the same difficulty I had, the following code did the job of checking to see if an IEnumerable was grouped or not (based off of Mr. Skeet's fancy-ass idea of using the dynamic keyword):

    public static bool IsGrouped (dynamic test) {
        return CheckGrouping(test);
    }
    static bool CheckGrouping(object o ) {
        return false;
    }
    static bool CheckGrouping<TKey, TValue>(IEnumerable<IGrouping<TKey, TValue>> grouping) {
        return true;
    }

Assuming the code is the same as above:

IsGrouped(dict); //false
IsGrouped(grouped); //true

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

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

发布评论

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

评论(1

真心难拥有 2025-01-09 12:53:01

在 .NET 4 中,结果不仅是可能的,而且是预期的 - 在 .NET 3.5 中,由于缺乏通用方差,最终结果将为 False。

IGroupingTKeyTValue 中都是协变的,KeyValuePair 是一个结构体,因此不能以协变的方式使用。

因此,IGrouping 是一个 IGrouping,但也是一个 IGrouping> 不是。

不是框架中的错误。至于如何找出某些TKey, TValue对是否实现了IGrouping,你可以自己努力工作,或者使用dynamic 尝试提供帮助:

// Code as before...
dynamic dyn = grouped;
ShowGrouping(dyn);

private static void ShowGrouping<TKey, TValue>
   (IEnumerable<IGrouping<TKey, TValue>> grouping)
{
    Console.WriteLine("TKey = {0}, TValue = {1}", typeof(TKey), typeof(TValue));
}

private static void ShowGrouping(object notGrouped)
{
    Console.WriteLine("Not a grouping");
}

请注意,这当然不是万无一失的 - 但它可能足以满足您的需要。

The results are not just possible but expected under .NET 4 - in .NET 3.5, the final result would be False due to the lack of generic variance.

While IGrouping<out TKey, out TValue> is covariant in both TKey and TValue, KeyValuePair<Tkey, TValue> is a struct, and therefore cannot be used in a covariant manner.

So an IGrouping<string, string> is an IGrouping<object, object>, but an IGrouping<string, KeyValuePair<int, string>> is not.

This is not a bug in the framework. As for how to find out whether something implements IGrouping<TKey, TValue> for some TKey, TValue pair, you could either work quite hard yourself, or using dynamic to try to help:

// Code as before...
dynamic dyn = grouped;
ShowGrouping(dyn);

private static void ShowGrouping<TKey, TValue>
   (IEnumerable<IGrouping<TKey, TValue>> grouping)
{
    Console.WriteLine("TKey = {0}, TValue = {1}", typeof(TKey), typeof(TValue));
}

private static void ShowGrouping(object notGrouped)
{
    Console.WriteLine("Not a grouping");
}

Note that this certainly isn't foolproof - but it may be good enough for what you need.

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