似乎在.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;
}
答案 0 :(得分:10)
我认为这基本上是由于ECMA 335的第8.7节。
基本上我们正在查看两个枚举类型之间的 assignable-to 关系。据我所知,8.7.2适用:
当且仅当以下之一成立时,位置类型T与位置类型U兼容。
- 根据§8.7.1中的定义,T和U不是托管指针类型,T是与 U兼容。
醇>
所以我们看看8.7.1并找到子弹5:
T是从零开始的秩-1阵列V [],U是从零开始的秩-1阵列W [],并且V是与元素兼容的 W
所以现在我们对两个枚举类型是否具有 array-element-compatible-with 关系感兴趣...然后导致:
签名类型T是与数据元素兼容的 - 具有签名类型U当且仅当T具有基础类型V且U具有基础类型W并且:或者
- V与W兼容;或
- V和W具有相同的缩减类型。
醇>
现在枚举的基础类型由此定义:
类型T的基础类型如下:
- 如果T是枚举类型,则其基础类型是枚举定义中声明的基础类型。
- [与我们无关]
醇>
所以,例如:
enum Foo : int {}
enum Bar : int {}
两者的基础类型都是int
。
现在我们可以回到 array-element-compatible-with 定义,看看V和W都是int
。由于8.7.1的第一个项目符号
签名类型T与签名类型U兼容,当且仅当至少下列其中一个成立时。
- T与U相同。
醇>
因此,阵列是兼容的。
它们还与底层类型本身的数组兼容:
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;在查询中