有同事问起一个问题:
己写一个模板容器,需要实现IEnumerable<T>的接口,由于IEnumerable<T>派生于IEnumerable,所以要实现两个方法,一个是模板的IEnumerator<T> GetEnumerator ()另一个是普通的IEnumerator GetEnumerator ()
C#的函数重载不允许只有返回值不同的重载,所以这两个东西不能同时存在,咋拌呢?
这个问题,对于有一些.NET编程经验的人,显然是小Case。但对刚从VC或VB中转过来的程序员,可能因为不是很了解接口的使用,所以造成疑惑。
实际上,CLR中支持显示接口成员实现来解决此问题。
方法如下:
public class MyContainer<T> : IEnumerable<T>
{
....
public IEnumerator<T> GetEnumerator()
{
//具体实现
....
}
IEnumerator IEnumerable.GetEnumerator()
{
//一般做法就是简单调用范型的接口实现即可。
return GetEnumerator();
}
....
}
原理很简单:IEnumerable.GetEnumerator在编译时是不同的方法名,并且实际上还要求使用IEnumerator对象引用时方法IEnumerable.GetEnumerator才会被调用。
注意:这种做法要求IEnumerable.GetEnumerator的前面不要加任何访问修饰符。当我们使用范型实例时,它是私有方法。是IEnumerable对象引用时,它成为公有方法。编译器自动生成了相应的处理,所以,不允许在这里加限定符。
其实这种方式不在范型时也大量使用,它是避免多余装箱操作的重要方法。比如最基本的Int32,他实现了IConvertible,但为了避免接口实现时的装箱,它定义了显示的实现。
对于显示接口成员实现,编译器做了些手脚,所以,用起来并不是很直观,只能是强制记忆了。以上的实现方法在MSDN中有详细的示例和介绍。
己写一个模板容器,需要实现IEnumerable<T>的接口,由于IEnumerable<T>派生于IEnumerable,所以要实现两个方法,一个是模板的IEnumerator<T> GetEnumerator ()另一个是普通的IEnumerator GetEnumerator ()
C#的函数重载不允许只有返回值不同的重载,所以这两个东西不能同时存在,咋拌呢?
这个问题,对于有一些.NET编程经验的人,显然是小Case。但对刚从VC或VB中转过来的程序员,可能因为不是很了解接口的使用,所以造成疑惑。
实际上,CLR中支持显示接口成员实现来解决此问题。
方法如下:
public class MyContainer<T> : IEnumerable<T>
{
....
public IEnumerator<T> GetEnumerator()
{
//具体实现
....
}
IEnumerator IEnumerable.GetEnumerator()
{
//一般做法就是简单调用范型的接口实现即可。
return GetEnumerator();
}
....
}
原理很简单:IEnumerable.GetEnumerator在编译时是不同的方法名,并且实际上还要求使用IEnumerator对象引用时方法IEnumerable.GetEnumerator才会被调用。
注意:这种做法要求IEnumerable.GetEnumerator的前面不要加任何访问修饰符。当我们使用范型实例时,它是私有方法。是IEnumerable对象引用时,它成为公有方法。编译器自动生成了相应的处理,所以,不允许在这里加限定符。
其实这种方式不在范型时也大量使用,它是避免多余装箱操作的重要方法。比如最基本的Int32,他实现了IConvertible,但为了避免接口实现时的装箱,它定义了显示的实现。
对于显示接口成员实现,编译器做了些手脚,所以,用起来并不是很直观,只能是强制记忆了。以上的实现方法在MSDN中有详细的示例和介绍。