每个枚举数组都实现了IEnumerable <everyotherenum>。我该如何解决这个问题?</everyotherenum>

时间:2011-10-19 22:21:03

标签: c# .net types enums

似乎在.NET中,“枚举数组”不是强类型概念。 MyEnum[]不仅被视为IEnumerable<MyEnum>,还被视为IEnumerable<YourEnum>。 (起初我也不相信。)

// Returns true:
typeof(IEnumerable<DayOfWeek>).IsAssignableFrom(typeof(AttributeTargets[]))

// Outputs "3":
var listOfLists = new List<object> {
    new[] { AttributeTargets.All },
    new[] { ConsoleColor.Blue },
    new[] { PlatformID.Xbox, PlatformID.MacOSX }
};
Console.WriteLine(listOfLists.OfType<IEnumerable<DayOfWeek>>().Count());

因此,当我查看实现IEnumerable<T>的所有内容的列表时,我得到了T[]List<T>以及迭代器生成的IEnumerable<T> s,但我也得到了我不想要的SomethingElse[]

最简单的方法是找出给定的Type(如上面的IsAssignableFrom)或给定的实例(与上面的OfType<T>一样)是否真实实现,说,IEnumerable<DayOfWeek>


我向Skeet先生提供了绿色复选标记,但是一旦我将他的代码放入Visual Studio,ReSharper建议使用更简洁的版本。使用您喜欢的任何版本。

public static IEnumerable<IEnumerable<T>> OfSequenceType<T>
    (this IEnumerable source) where T : struct
{
    return from sequence in source.OfType<IEnumerable<T>>()
           let type = sequence.GetType()
           where !type.IsArray || type.GetElementType() == typeof (T)
           select sequence;
}

2 个答案:

答案 0 :(得分:10)

我认为这基本上是由于ECMA 335的第8.7节。

基本上我们正在查看两个枚举类型之间的 assignable-to 关系。据我所知,8.7.2适用:

  

当且仅当以下之一成立时,位置类型T与位置类型U兼容。

     
      
  1. 根据§8.7.1中的定义,T和U不是托管指针类型,T是 U兼容。
  2.   

所以我们看看8.7.1并找到子弹5:

  

T是从零开始的秩-1阵列V [],U是从零开始的秩-1阵列W [],并且V是与元素兼容的 W

所以现在我们对两个枚举类型是否具有 array-element-compatible-with 关系感兴趣...然后导致:

  

签名类型T是与数据元素兼容的 - 具有签名类型U当且仅当T具有基础类型V且U具有基础类型W并且:或者

     
      
  1. V与W兼容;或
  2.   
  3. V和W具有相同的缩减类型。
  4.   

现在枚举的基础类型由此定义:

  

类型T的基础类型如下:

     
      
  1. 如果T是枚举类型,则其基础类型是枚举定义中声明的基础类型。
  2.   
  3. [与我们无关]
  4.   

所以,例如:

enum Foo : int {}
enum Bar : int {}

两者的基础类型都是int

现在我们可以回到 array-element-compatible-with 定义,看看V和W都是int。由于8.7.1的第一个项目符号

,因此类型本身兼容
  

签名类型T与签名类型U兼容,当且仅当至少下列其中一个成立时。

     
      
  1. T与U相同。
  2.   

因此,阵列是兼容的。

它们还与底层类型本身的数组兼容:

enum Foo {}
...
object x = new int[10];
Foo[] y = (Foo[]) x; // No exception

请注意,x必须在此处声明为object,以说服C#编译器此可能合法 - 否则它遵循C#语言的规则,不太宽容......


至于你的第二个问题:

  

最简单的方法是找出给定的Type(如上面的IsAssignableFrom)或给定的实例(与上面的OfType一样)是否真正实现了IEnumerable?

可以只是特殊情况数组,因为它们的行为有点奇怪。坦率地说,这可能是最简单的方法。我尝试使用Type.GetInterfaceMap,但这也给出了一个问题:

  

未处理的异常:System.ArgumentException:通用接口的接口映射   数组上的aces无法重试。

(是的,最后的输入错误确实在错误信息中。虽然不能为此提出连接问题而烦恼...)

我强烈怀疑特殊外壳是前进的方式......例如,假设你知道你正在处理一个值类型(引用类型数组的协方差是另一回事。 ..)

public static IEnumerable<IEnumerable<T>> OfSequenceType<T>
    (this IEnumerable source) where T : struct
{
    // Nullity check elided...
    foreach (object x in source)
    {
        IEnumerable<T> sequence = x as IEnumerable<T>;
        if (sequence == null)
        {
            continue;
        }
        // Work around odd value type array variance
        Type type = sequence.GetType();
        if (type.IsArray && type.GetElementType() != typeof(T))
        {
            continue;
        }
        yield return sequence;
    }
}

答案 1 :(得分:1)

我试过了:

var listOfLists = new List<object> {
    new[] { AttributeTargets.All },
    new[] { ConsoleColor.Blue },
    new[] { PlatformID.Xbox, PlatformID.MacOSX },
    new[] { DayOfWeek.Friday, DayOfWeek.Saturday }
};
Console.WriteLine(listOfLists.Where(obj => obj.GetType() == typeof(DayOfWeek[])).Count());

结果我得了1分。我还在寻找你如何使用IEnumerable&lt; DayOfWeek&gt;在查询中

相关问题