一个具有多个IEnumerable 接口的类 – 如何处理非generics方法?

我想我理解为什么IEnumerableinheritance自IEnumerable ,在阅读post之后: 为什么IEnumerable从IEnumerableinheritance?

但是,我不确定在应用2个通用接口时如何最好地实现非generics方法? 这是我正在编写的代码的示例:

 public interface IComponentA { /* ... Interface A Code ... */ } public interface IComponentB { /* ... Interface B Code ... */ } public class ComponentModel: IEnumerable, IEnumerable { public ComponentModel() { } private List ListOfComponentA = new List(); private List ListOfComponentB = new List(); // ... Some public methods to add and remove components (for A and B). IEnumerator IEnumerable.GetEnumerator() { return ListOfComponentA.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return ListOfComponentB.GetEnumerator(); } // The fact that IEnumerable inherits from the non-generic IEnumerable // now means I have to deal with this. IEnumerator IEnumerable.GetEnumerator() { // Throwing a NotImplementedException is probably not a good idea // so what should I put in here? throw new NotImplementedException(); } } 

欢迎提出有关非通用方法的建议。

我自己可能不会这样做。 对于用户来说,让枚举器枚举不同的东西可能会让人感到困惑,这取决于调用它的接口引用,当然还有generics返回的问题。

相反,您可以将列表的只读版本公开为迭代器:

 public class ComponentModel { public ComponentModel() { } private List ListOfComponentA = new List(); private List ListOfComponentB = new List(); public IEnumerable AComponents { get { return ListOfComponentA.Skip(0); } } public IEnumerable BComponents { get { return ListOfComponentB.Skip(0); } } ... } 

通过使用Skip(0)返回一个迭代器,它可以防止它们返回List并从你下面修改List

你当然也可以使用ReadOnlyCollection ,但是当你尝试做变异操作时它们会抛出,这些有点笨拙。

所以现在,你可以迭代:

 foreach(var a in myModel.AComponents) { ... } foreach(var b in myModel.BComponents) { ... } 

此外, IF A和B组件列表总是具有相同的长度,您可以在.NET 4.0中使用Linq Zip()方法在它们的Tuple上有一个枚举器:

 public IEnumerable> Components { get { return ListOfComponentA.Zip(ListOfComponentB, (a,b) => Tuple.Create(a,b)); } } 

接受的答案是完全正确的; 你应该将具有两个序列的东西实现为具有两个序列,而不是两个序列。

到目前为止,为什么它是一个坏主意的原因是足够的,即,当你选择组合而不是inheritance时,它通常不那么令人困惑。 但是,我认为指出实现两个不同的IEnumerable接口是一个非常糟糕的想法还有另一个原因: 我们在C#4中向IEnumerable添加了通用协方差。

通用协方差意味着您可以将一系列海龟传递给采用一系列动物的方法,因为海龟是动物。 那么在这种情况下运行时会做什么呢?

 class Weird : IEnumerable, IEnumerable { ... } ... Weird weird = whatever; foreach(Animal animal in weird) { ... 

animal是乌龟还是长颈鹿? 运行时必须选择其中一个,并且完全不清楚哪一个是正确的选择。 这是C#规范没有说明会发生什么的罕见情况之一; 这是实现定义的行为。 避免,避免,避免。

猫不是一系列的腿,眼睛和胡须。 相反,它一系列的腿,眼睛和胡须。 inheritance的构成

而不是将ComponentModel视为IComponentAIComponentB两个完全不相关的序列,您应该删除它并只添加方法:

 public IEnumerable GetSequenceOfComponentA() { // } public IEnumerable GetSequenceOfComponentB() { // } 

(你甚至期望foreach(var x in componentModel) { // }做什么?这里发生了什么: public void M(IEnumerable a) { }public void M(IEnumerable b) { }和那么M(componentModel) ?)

也许这些方面的东西会起作用。 它做一个公共类MyCollection(T):IEnumerable(T)使用相同的类型来处理2种不同类型的数据

你可以进一步使用MyCollection(T,X,Y,Z):IEnumerable(T)其中X,Y,Z是你的其他类型的列表,除了T将是你的主迭代器在内部运行并行地迭代你的其他列表。

 public class Program { public static void Main(string[] args) { Console.WriteLine("Start....."); for ( int i = 0; i < 10; i++) { IEnumerable collection; Console.WriteLine(); if (i % 2 == 0) { Console.Write("Ints..... "); collection = new MyCollection(new int[] { 1,2,3 }); } else { Console.Write("Strings..... "); collection = new MyCollection(new string[] { "x","y","z" } ); } foreach (var item in collection) { Console.Write(item); } Console.WriteLine(); } Console.WriteLine(); Console.WriteLine("End....."); Console.ReadLine(); } } public class MyCollection : IEnumerable { private T[] _Tdata; public MyCollection4(T[] arrayOfT) { _Tdata = arrayOfT; } public IEnumerator GetEnumerator() { var listofT = new List(_Tdata); return listofT.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } }