Office中国论坛/Access中国论坛
标题:
【转载】关于IEnumerable 是否应该继承IEnumerable(老外讨论的很多)
[打印本页]
作者:
faunus
时间:
2014-2-24 11:30
标题:
【转载】关于IEnumerable 是否应该继承IEnumerable(老外讨论的很多)
关于IEnumerable <T>是否应该继承IEnumerable,老外讨论的很多!
http://blogs.msdn.com/brada/archive/2005/01/18/355755.aspx
http://morganchengmo.spaces.live ... 8939932E!1458.entry
Should IEnumerable <T> inherits from IEnumerable?
.Net 2.0引入了Generics(泛型)的概念,原有的在System.Collectionis namespace下的接口几乎都在System.Collections.Generic namesapce下多了一个对应的Generic接口,不过奇怪的是IList <T>不是继承自IList的,而IEnumerable <T>是继承自IEnumerable的。
Brad Abrams有一篇Blog解释了为什么,但是实际上他只解释了为什么IList <T>没有继承IList。以他的观点,理想状况下,所有的新的支持Generic的 interface都应该继承以前对应的interface,但是如果让IList <T>继承IList的话,那么是实现 IList <int>的类就需要实现两个Insert方法,一个是IList <int>的void Insert(int index, int item),另外一个是IList的void Insert(int index, object item),这样对一个类对象obj,调用obj.Insert(0, 123)和调用obj.Insert(0, "abc")都是合法的,这不是我们想要的,因为我们既然继承IList <int>,就希望编译器能够做好类型检查,不让非int的物体插进来,但是这个继承关系造成了这样局面,所以IList <T>不继承IList。
上面IList <T>不应继承 IList的理由很充分,但是并不足以说明IEnumerable <T>就该继承IEnumerable。当然,因为T对 IEnumerable而言,只有“输出”作用,不像IList一样既有“输入”作用,也有“输出”作用,所以安全,但是,比较不爽的就是,每个实现 IEnumerable <T>的类,不得不实现两个GetEnumerator,MSDN的sample code并没有强调这一点,弄得很多新手(包括我:)一开始只实现了IEnumerable <T>.GetEnumerator,被编译器的出错提示搞得莫名其妙。
我觉得就不应该让IEnumerable <T>继承IEnumerable,虽然这个继承关系似乎不违反LSP,但是我觉得LSP只是一个必要条件,不是充分条件。如果谁想让一个类 既能是IEnumerable,又能是 IEnumerable <T>,那就同时实现这两个interface好了,就和IList <T>一样:
作者:
faunus
时间:
2014-2-24 11:31
[size=14.399999618530273px]加一点测试用代码:
[size=14.399999618530273px]
[size=14.399999618530273px]
using System;
using System.Collections;
using System.Collections.Generic;
public class GenericList<T> : System.Collections.Generic.IEnumerable<T>
{
protected Node head;
protected Node current = null;
protected class Node
{
public Node Next { get; set; }
public T Data { get; set; }
public Node(T t)
{
Next = null;
Data = t;
}
}
public GenericList()
{
head = null;
}
public void Add(T t)
{
Node n = new Node(t);
n.Next = head;
head = n;
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()//显式接口定义
//public IEnumerator<T> GetEnumerator()//隐式接口定义
{
Console.WriteLine("开始执行:IEnumerable<T>");
Node current = head;
while (current != null)
{
yield return current.Data;
current = current.Next;
}
}
//IEnumerator GetEnumerator()//隐式接口定义
IEnumerator IEnumerable.GetEnumerator()//显式接口定义
{
//return GetEnumerator();
//return IEnumerable<T>.GetEnumerator();
Console.WriteLine("开始执行:IEnumerable");
Node current = head;
while (current != null)
{
yield return current.Data;
current = current.Next;
}
}
}
class MyClass
{
static void Main(string[] args)
{
GenericList<int> list = new GenericList<int> { 1, 2, 3, };
//定义在类上
GenericList<int> ieC = list;
foreach (var jC in ieC)
{
Console.WriteLine(jC);
}
//定义在显式接口上
IEnumerable<int> ieT = list;
foreach (var jT in ieT)
{
Console.WriteLine(jT);
}
//定义在隐式接口上
IEnumerable ie = list;
foreach (var j in ie)
{
Console.WriteLine(j);
}
}
}
//T Current { get; }//IEnumerable<T>专有
//object Current { get; }//IEnumerable专有
//bool MoveNext();
//void Reset();
//为什么新增加的泛型接口IEnumerable<T>要继承IEnumerable,这是为了兼容。
//理论上所有的泛型接口都要继承自所有的非泛型接口。
//例如在.net 1.1中有个方法接收的是IEnumerable类型的参数,
//当移植到新的环境下,我们传入一个IEnumerable<T>的参数,
//它也是可以被接受的,因为他们完成的都是枚举的行为。
//然而特殊的是IList<T>没有继承自IList接口,
//因为如果让IList<T>继承 IList的话,
//那么是实现IList<int>的类就需要实现两个Insert方法,
//一个是IList<int>的void Insert(int index, int item),
//另外一个是IList的void Insert(int index, object item),
//这是就有一个接口可以把object类型的数据插入到IList<int>集合中了,
//这是不对的,所以不继承。
//而IEnumerable<T>不同的是,它只有”输出“的作用,
//也就是说我们只会从它里面取数据,
//所以不会有上面描述的混乱出现。
//.NET Framework使用IEnumerable<T>表示一个关系(集合),但反之不然。
//IEnumerable<T>的本质是一个序列枚举器,本身就具备三重特性,集合、关系、序列。
复制代码
作者:
faunus
时间:
2014-2-24 11:31
/T Current { get; }//IEnumerable<T>专有
//object Current { get; }//IEnumerable专有
//bool MoveNext();
//void Reset();
//为什么新增加的泛型接口IEnumerable<T>要继承IEnumerable,这是为了兼容。
//理论上所有的泛型接口都要继承自所有的非泛型接口。
//例如在.net 1.1中有个方法接收的是IEnumerable类型的参数,
//当移植到新的环境下,我们传入一个IEnumerable<T>的参数,
//它也是可以被接受的,因为他们完成的都是枚举的行为。
//然而特殊的是IList<T>没有继承自IList接口,
//因为如果让IList<T>继承 IList的话,
//那么是实现IList<int>的类就需要实现两个Insert方法,
//一个是IList<int>的void Insert(int index, int item),
//另外一个是IList的void Insert(int index, object item),
//这是就有一个接口可以把object类型的数据插入到IList<int>集合中了,
//这是不对的,所以不继承。
//而IEnumerable<T>不同的是,它只有”输出“的作用,
//也就是说我们只会从它里面取数据,
//所以不会有上面描述的混乱出现。
//.NET Framework使用IEnumerable<T>表示一个关系(集合),但反之不然。
//IEnumerable<T>的本质是一个序列枚举器,本身就具备三重特性,集合、关系、序列。
欢迎光临 Office中国论坛/Access中国论坛 (http://www.office-cn.net/)
Powered by Discuz! X3.3