Detecting if IEnumerable <T> is grouped, I get some crazy results on type checking
So, I'm trying to find out if any random IEnumerable passed to my method is grouped. The idea is that I will process grouped data in different ways. My problem is that IGrouping<> is a generic interface that does not implement a non-generic interface, and for some reason I cannot verify it with the is statements.
To test this, 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>); The 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 if I do not know the type of grouped values, I canβt check if it is grouped? Is this a bug in the .Net Framework?
How can you make the results higher?
EDIT: John Skeet's answer was dead ... As a courtesy to someone who was here with the same difficulty as me, the following code checked to see if IEnumerable is grouped or not (based on Mr. Skeet's idea fancy using a 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 The results are not just possible, but expected in .NET 4 - in .NET 3.5, the final result will be False due to the lack of general variance.
While IGrouping<out TKey, out TValue> is covariant in both TKey and TValue , KeyValuePair<Tkey, TValue> is a structure and therefore cannot be used in a covariant manner.
So, IGrouping<string, string> is IGrouping<object, object> , but IGrouping<string, KeyValuePair<int, string>> not.
This is not a mistake in the structure. As for how to find out if IGrouping<TKey, TValue> for some pair of TKey, TValue , you can either work quite hard on your own or use 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"); } Please note that this is certainly not reliable - but it may be good enough for what you need.