什么是EIMI的好用例?

时间:2009-01-23 12:53:20

标签: c# .net interface

EIMI是一个显式的接口成员实现。所以而不是:

public int SomeValue{get;}

你有

int SomeInterface.SomeValue {get;}

我正在考虑使用一个,因为我正在使用内部接口(解耦,但限制),我不想让实现对象上的方法出现在它的公共API中。

这是一个很好的用例吗?

4 个答案:

答案 0 :(得分:7)

一个非常好的例子是.Net泛型集合类。

例如,List<T>显式实现'IList'和IList(非通用接口)。这意味着当您直接使用该类时,您将只看到专门的方法,而不是使用Object的方法。

假设您实例化List<Person>。如果IList是隐式实现的,那么你可以在类Add(Person item)和Add(Object item)上直接访问两个add方法,这将破坏泛型提供的类型安全性。调用list.Add(“Foo”)将编译得很好,因为将自动选择Add(Object)重载,并且泛型提供的类型安全性已经消失。

答案 1 :(得分:4)

是的,这是一个很好的用例。根据MSDN上的C# Language Specification

  

显式接口成员实现有两个主要目的:

     
      
  • 由于无法通过类或结构实例访问显式接口成员实现,因此它们允许从类或结构的公共接口中排除接口实现。当类或结构实现内部接口时,这对于该类或结构的使用者不感兴趣时​​,这尤其有用。

  •   
  • 显式接口成员实现允许使用相同签名消除接口成员的歧义。如果没有显式的接口成员实现,那么类或结构将不可能具有相同签名和返回类型的接口成员的不同实现,因为类或结构不可能在所有接口成员上具有任何实现。相同的签名但具有不同的退货类型。

  •   

答案 2 :(得分:2)

从书籍CLR到C#,您可以找到使用EIMI的其他原因:类型安全和拳击避免

例如,您已实现IComparable接口:

struct SomeValueType1 : IComparable
{
    private int _v;

    public SomeValueType1(int v)
    {
        _v = v;
    }

    public int CompareTo(object obj)
    {
        return _v - ((SomeValueType1)obj)._v;
    }
}

查看方法CompareTo的实现: 不安全。作为参数,它得到了对象。如果对象的类型不是SomeValueType1 - 它将在运行时崩溃

使用:

SomeValueType1 svt1 = new SomeValueType1(0);
Object o1 = new Object();
Int32 res = svt1.CompareTo(svt1);
res = svt1.CompareTo(o1);

第三行从svt1装箱到对象。第4行将生成运行时错误

让我们使用EIMI:

struct SomeValueType2 : IComparable
{
    private int _v;

    public SomeValueType2(int v)
    {
        _v = v;
    }

    public int CompareTo(SomeValueType2 svt2)
    {
        return _v - svt2._v;
    }

    int IComparable.CompareTo(object obj)
    {
        return CompareTo((SomeValueType2)obj);
    }
}

使用:

SomeValueType2 svt2 = new SomeValueType2(0);
Object o2 = new Object();
res = svt2.CompareTo(svt2);
res = svt2.CompareTo(o2);
第三行不做拳击!第4行将生成编译时错误

正如Jeffrey Richter在CLR中通过C#第4版所写的那样:&#34;这个讨论清楚地告诉你EIMI应该非常谨慎地使用。当许多开发人员首次了解EIMI时,他们认为他们很酷并且他们会尽可能地开始使用它们。不要这样做! EIMI在某些情况下很有用,但是你应该尽可能地避免它们,因为它们使用了很多类型 更难。&#34;

祝你好运!

答案 3 :(得分:2)

我想澄清一下“界面成员的歧义消除”是什么意思(Vojislav Stojkovic,第二个例子):

public interface IWindow {
   Object GetMenu();
}

public interface IRestaurant {
    Object GetMenu();
}

两个不同的接口具有相同名称和标志的方法。但是我们想要实现两个接口:

public sealed class MarioPizzeria : IWindow, IRestaurant  {
    //Explicit inteface member implementation for IWindow      
    Object IWindow.GetMenu();

    //Explicit inteface member implementation for IRestaurant
    Object IRestaurant.GetMenu();

    //An optional method that has nothing to do with an interface
    public Object GetMenu(); 
}

用法:

MarioPizzeria mp = new MarioPizzeria();
mp.GetMenu(); //MarioPizzeria's public method

//IWindow.GetMenu method
IWindow window = mp;
window.GetMenu();

//IRestaurant.GetMenu method
IRestaurant restaurant = mp;
restaurant.GetMenu();

一个有趣的fact

  • 无法访问显式接口成员实现 类或结构实例。
  • 隐式接口成员实现必须始终公开。