C#中的接口

Posted

技术标签:

【中文标题】C#中的接口【英文标题】:Interface in C# 【发布时间】:2011-01-10 23:45:08 【问题描述】:

我是 OOP 新手,有一些问题。

    为什么接口中声明的方法不能有修饰符(公共、私有等)。

    在此代码中:

class Program

    static void Main(string[] args)
    
        X ob = new Y();
        ob.add(4, 5);
        Z ob1 = new Y();
        ob1.mull(2, 3);
        Console.Read();
    


public interface X

    void add(int x, int y);

public interface Z

    void mull(int x, int y);


class Y : X, Z

    void X.add(int x, int y)//here we are not decalring it as public ,why?
    
        Console.WriteLine("sum of X and y is " + (x + y));
    
    void Z.mull(int x, int y)
    
        Console.WriteLine("product of X and Y is" + (x * y));
    

这两种方法都不需要修饰符,但是当我不使用接口时,比如上面的X.add(),我需要将实现公开。为什么?

【问题讨论】:

***.com/questions/1652123/… 的可能重复项 【参考方案1】:

接口是一种契约。它说“我可以做这些事情”。有人给你一个 IInterface 的实例,你不能使用该合同中的某些方法,因为它们已被标记为不公开,这有什么意义?

这就是以这种方式设计语言的基本原理。这方面的规范在语言规范的 §13.2 中:

所有接口成员都隐含地具有公共访问权限。接口成员声明包含任何修饰符是编译时错误。特别是,接口成员不能使用修饰符abstractpublicprotectedinternalprivate,virtualoverridestatic 声明。

至于您的代码,这是explicit interface implementation 的示例。当一个类或结构实现两个接口时,它最有用,每个接口都有一个具有相同签名的成员。例如,IEnumerableIEnumerable<T> 都定义了一个方法 GetEnumerator 不接受任何参数。

public interface IEnumerable 
    IEnumerator GetEnumerator();


public interface IEnumerable<T> : IEnumerable 
    IEnumerator<T> GetEnumerator();

请注意,根据上述定义,任何实现IEnumerable&lt;T&gt; 的类也必须实现IEnumerable。请记住,返回类型不是签名的一部分,因此我们与IEnumerable.GetEnumeratorIEnumerable&lt;T&gt;.GetEnumerator 有冲突。这就是显式接口实现要解决的问题:

class X<T> : IEnumerable<T> 
    List<T> _list = new List<T>();
    public IEnumerator<T> GetEnumerator() 
        return _list.GetEnumerator();
    

    IEnumerator GetEnumerator() 
        return GetEnumerator(); // invokes IEnumerable<T>.GetEnumerator
    

显式接口实现的成员仅通过接口实例可见。因此:

X<int> x = new X<int>();
var e1 = x.GetEnumerator(); // invokes IEnumerable<int>.GetEnumerator
                           // IEnumerable.GetEnumerator is not visible
IEnumerable y = x;
var e2 = y.GetEnumerator(); // invokes IEnumerable.GetEnumerator

因此,在您的代码中

X ob = new Y();
ob.add(1, 2); // X.add is visible through interface
Y y = new Y();
y.add(1, 2); // compile-time error, X.add is not visible

这两种方法都不需要修饰符,但是当我不使用接口时,比如上面的 X.add(),我需要将实现公开。为什么?

好的,目前尚不清楚您在此问的是什么。显式接口实现不允许访问修饰符。这是 13.4:

显式接口成员实现包含访问修饰符是编译时错误,包含修饰符abstractvirtualoverridestatic 是编译时错误。

如果接口实现未标记为显式接口实现,则它必须具有访问修饰符public。这是 13.4.4(接口映射):

类或结构C 的接口映射为C 的基类列表中指定的每个接口的每个成员定位一个实现。特定接口成员I.M 的实现,其中I 是声明成员M 的接口,是通过检查每个类或结构S 来确定的,从C 开始并为每个连续的重复C 的基类,直到找到匹配项

如果S 包含与IM 匹配的显式接口成员实现的声明,则该成员是I.M 的实现

否则,如果S 包含与M 匹配的非静态公共成员的声明,则该成员是I.M 的实现。

如果无法找到C 的基类列表中指定的所有接口的所有成员的实现,则会发生编译时错误。

所以,简而言之,编译器首先寻找显式接口实现。如果找不到,那么它会寻找一个 non-static, public 成员,该成员与正在实现的方法 M 具有相同的签名。如果找不到,则会发生编译时错误。所以规则是这样的。实现接口成员I.M

    如果你明确地实现I.M,那么语法是

    return-type I.M(parameter-list)

    否则语法为

    public return-type M(parameter-list)

因此,与

interface IAdd 
    int Add(int x, int y)

我们可以显式地实现:

class Explicit : IAdd 
    int IAdd.Add(int x, int y)  return x + y; 

或不:

class NotExplicit : IAdd 
    public int Add(int x, int y)  return x + y; 

不同之处在于Explicit.Add 不可见,除非Explicit 的实例被键入为IAdd

IAdd explicitInterface = new Explicit();
explicitInterface.Add(2, 2);
Explicit explicit = new Explicit();
explicit.Add(2, 2); // compile-time error

IAdd notExplicitInterface = new NotExplicit();
notExplicitInterface.Add(2, 2);
NotExplicit notExplicit = new NotExplicit();
notExplicit.Add(2, 2); // okay, NOT a compile-time error as above

这有帮助吗?

【讨论】:

这个答案非常彻底。 您的简短回答中一定缺少一些东西。我还在找……【参考方案2】:

界面就像一个联系人。当一个类实现某个接口时,您可以保证该接口成员存在于该类中。如果可以改变可见性,那么它就行不通了。

您可能想看看这些问题:

How will I know when to create an interface? Why can’t I have protected interface members?

【讨论】:

【参考方案3】:

因为接口成员是自动公开的。您正在通过接口定义合同,成员不公开没有任何意义,因为您必须在实现类中实现它们。

【讨论】:

【参考方案4】:

直接来自Microsoft:“接口成员始终是公共的,因为接口的目的是使其他类型能够访问类或结构。”

【讨论】:

您可能需要修复您的链接。【参考方案5】:

由于您的两个接口没有定义具有相同签名的方法,因此您不需要显式实现。您可以执行以下操作:

public void add(int x, int y)

    Console.WriteLine("sum of X and y is " + (x + y));

public void mull(int x, int y)

    Console.WriteLine("product of X and Y is" + (x * y));

这是接口的隐式实现,现在在类的实例上调用这些方法更容易。只需调用myInstance.add(1, 2) 而不必强制转换myInstance 成为接口X 的实例。

【讨论】:

【参考方案6】:

我将备份并解释您报告的症状,而不是试图解释为什么不需要 public 修饰符;其他答案已经充分解释了这一点。

您感到困惑的原因可能是您使用的是显式接口实现。使用显式接口实现时,需要先将对象实例转换为该接口类型,然后才能调用其方法。

如果您删除“X”。从您的 X.Add 实现中,您将能够“看到”并使用该接口,而无需显式强制转换。这是“隐式”接口实现。只要您没有任何名称冲突,或者出于某种原因使接口成员对普通客户端的可见度稍微降低,您可能希望更喜欢隐式接口实现。

【讨论】:

【参考方案7】:

因为在接口中声明的函数、字段等默认总是有 public 修饰符。因此,在实现它时,您不必键入 public,因为类现在方法是接口实现,因此它是公共的。在类中,所有字段和方法都是私有的,但是是聋的。

【讨论】:

【参考方案8】:

这是接口的Explict 和Implict 实现之间的区别。

您通常希望隐式实现接口,这意味着实现的成员是公开可用的。当您考虑实现接口通常表示类可以执行给定功能(例如通过 IDisposable 释放)时,这是有道理的。

在您需要一种类型来实现接口但不希望这些接口成员可公开访问的场景中,您可以使用显式实现。成员仍然可以访问,但只有在通过接口引用类型时才能访问。

【讨论】:

以上是关于C#中的接口的主要内容,如果未能解决你的问题,请参考以下文章

C#中的接口

为啥 C# 中的集合类(如 ArrayList)继承自多个接口,如果其中一个接口继承自其余接口?

谈谈C#中的接口

C# 中的抽象显式接口实现

c#中的行为抽象类和接口是啥? [复制]

C#中的继承与接口[重复]