在C#中实现接口和显式实现接口的区别

24

我在VS2010中有两个选项来实现接口。

此处插入图片描述

当我有如下的 IHelper.cs 接口:

public interface IHelper
    ....
    IEnumerable<IPort> Ports { get; }

“显式实现接口”会给出以下代码:

    IEnumerable<IPort> IHelper.Ports
    {
        get
        {
            ...
        }
    }

而且,“实现接口”给了我这段代码:

    public IEnumerable<IPort> Ports
    {
        get
        {
            ...
        }
    }

它们是相同的还是不同的?为什么在C#中实现接口有两种选项?


1
"实现公共接口"和"实现私有接口"会太难吗?" - PRMan
3个回答

38

显式接口声明意味着接口成员只能在该接口本身上使用,因此实现类型在公开访问它们之前需要将其强制转换为该接口。

隐式声明是实现大多数接口的标准方式,将接口项暴露在实现者类型的公共API上。

显式接口定义的主要原因是避免命名冲突,如果您碰巧实现了包含具有相同签名的方法的两个接口...显式定义允许编译器保持足够不同的签名以便解决问题。

支持代码维护的次要原因,如XenoPuTtSs在评论中建议的那样,是显式定义将在实现类型上触发编译器错误,如果删除了方法签名。对于隐式实现,从接口中删除方法会使该方法成为任何类型的常规成员 - 这意味着您现在需要手动搜索已失效的方法实现。


5
另外(这不是主要原因),当接口发生更改时(例如删除或更改方法),编译器将在明确定义接口的类上抛出错误,因为这些方法不再在接口上。这是一种有用的方式(依我之见)来定位大型项目中未使用的代码。 - XenoPuTtSs
@XenoPuTtSs 很好的观点,我已经修改了我的答案以包含这一点。 - Adam Houldsworth
1
另一个原因是:保留可选参数的默认值。 - marsze

9
它们是完全不同的。如果你显式地实现接口,你只能通过该接口的引用来引用接口成员。以下代码演示了这个思想。
public interface IFoo {
    String Bar { get; set; }
}
public class ImplicitFoo : IFoo {
    public string Bar {get;set;}
}
public class ExplicitFoo : IFoo {
    private String _Bar;
    string IFoo.Bar {
        get {
            return _Bar;
        }
        set {
            _Bar = value;
        }
    }
}
public class Test {
    public void Test() {
        var iml = new ImplicitFoo();
        // Works fine
        Console.WriteLine(iml.Bar);
        var expl = new ExplicitFoo();
        var fooInterface = (IFoo)expl;
        // Works fine
        Console.WriteLine(fooInterface.Bar);
        // Throws compile time exception
        Console.WriteLine(expl.Bar);
    }
}

8

实现接口的类可以显式实现该接口的成员。当成员被显式实现时,它不能通过类实例访问,只能通过接口实例访问。

// explicit1.cs
interface IDimensions 
{
  float Length();
  float Width();
}

class Box : IDimensions 
{
  float lengthInches;
  float widthInches;

 public Box(float length, float width) 
 {
    lengthInches = length;
   widthInches = width;
 }
 // Explicit interface member implementation: 
 float IDimensions.Length() 
 {
    return lengthInches;
 }
 // Explicit interface member implementation:
 float IDimensions.Width() 
 {
    return widthInches;      
 }

 public static void Main() 
 {
   // Declare a class instance "myBox":
   Box myBox = new Box(30.0f, 20.0f);
  // Declare an interface instance "myDimensions":
  IDimensions myDimensions = (IDimensions) myBox;
  // Print out the dimensions of the box:
  /* The following commented lines would produce compilation 
     errors because they try to access an explicitly implemented
     interface member from a class instance:                   */
  //System.Console.WriteLine("Length: {0}", myBox.Length());
  //System.Console.WriteLine("Width: {0}", myBox.Width());
  /* Print out the dimensions of the box by calling the methods 
     from an instance of the interface:                         */
  System.Console.WriteLine("Length: {0}", myDimensions.Length());
  System.Console.WriteLine("Width: {0}", myDimensions.Width());
 }
}

显式接口实现还允许程序员继承共享相同成员名称的两个接口,并为每个接口成员提供单独的实现。本示例显示了一个盒子的尺寸,包括公制和英制单位。Box类继承了两个接口IEnglishDimensions和IMetricDimensions,它们代表不同的测量系统。两个接口都具有相同的成员名称Length和Width。

请看示例:

// explicit2.cs
// Declare the English units interface:
interface IEnglishDimensions 
{
  float Length();
  float Width();
}
// Declare the metric units interface:
interface IMetricDimensions 
{
   float Length();
   float Width();
}
// Declare the "Box" class that implements the two interfaces:
// IEnglishDimensions and IMetricDimensions:
class Box : IEnglishDimensions, IMetricDimensions 
{
   float lengthInches;
   float widthInches;
 public Box(float length, float width) 
  {
    lengthInches = length;
    widthInches = width;
  }
// Explicitly implement the members of IEnglishDimensions:
float IEnglishDimensions.Length() 
{
  return lengthInches;
}
float IEnglishDimensions.Width() 
{
  return widthInches;      
}
 // Explicitly implement the members of IMetricDimensions:
float IMetricDimensions.Length() 
{
   return lengthInches * 2.54f;
}
float IMetricDimensions.Width() 
{
  return widthInches * 2.54f;
}
public static void Main() 
{
  // Declare a class instance "myBox":
  Box myBox = new Box(30.0f, 20.0f);
  // Declare an instance of the English units interface:
  IEnglishDimensions eDimensions = (IEnglishDimensions) myBox;
  // Declare an instance of the metric units interface:
  IMetricDimensions mDimensions = (IMetricDimensions) myBox;
  // Print dimensions in English units:
  System.Console.WriteLine("Length(in): {0}", eDimensions.Length());
  System.Console.WriteLine("Width (in): {0}", eDimensions.Width());
  // Print dimensions in metric units:
  System.Console.WriteLine("Length(cm): {0}", mDimensions.Length());
  System.Console.WriteLine("Width (cm): {0}", mDimensions.Width());
 }
}

查看文章获取更多详情。


1
最好将文章中相关的信息包含在答案本身中,链接并不可靠,可能不会像答案一样持久。如果链接失效,你的回答也无法提供帮助。 - Adam Houldsworth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接