C#接口。隐式实现与显式实现

C#接口。隐式实现与显式实现,c#,.net,interface,C#,.net,Interface,在C#中隐式实现接口和显式实现接口有什么区别 什么时候应该使用隐式,什么时候应该使用显式 其中一个有什么优点和/或缺点吗 Microsoft的官方指南(第一版)指出,不建议使用显式实现,因为它会给代码带来意想不到的行为 我认为,在国际奥委会之前的时间里,当你不把东西作为接口传递时,这条准则是非常有效的 任何人都可以触及这一方面吗?隐式是指通过类中的成员定义接口时Explicit是指在接口上的类中定义方法。我知道这听起来令人困惑,但我的意思是:IList.CopyTo将隐式实现为: public

在C#中隐式实现接口和显式实现接口有什么区别

什么时候应该使用隐式,什么时候应该使用显式

其中一个有什么优点和/或缺点吗


Microsoft的官方指南(第一版)指出,不建议使用显式实现,因为它会给代码带来意想不到的行为

我认为,在国际奥委会之前的时间里,当你不把东西作为接口传递时,这条准则是非常有效的


任何人都可以触及这一方面吗?

隐式是指通过类中的成员定义接口时Explicit是指在接口上的类中定义方法。我知道这听起来令人困惑,但我的意思是:
IList.CopyTo
将隐式实现为:

public void CopyTo(Array array, int index)
{
    throw new NotImplementedException();
}
并明确表示:

void ICollection.CopyTo(Array array, int index)
{
    throw new NotImplementedException();
}
区别在于隐式实现允许您通过将接口转换为该类和接口本身而创建的类来访问接口。显式实现允许您仅通过将接口转换为接口本身来访问接口

MyClass myClass = new MyClass(); // Declared as concrete class
myclass.CopyTo //invalid with explicit
((IList)myClass).CopyTo //valid with explicit.
我使用显式主要是为了保持实现干净,或者在需要两个实现时使用显式。不管怎样,我很少使用它

我确信有更多的理由使用/不使用其他人将发布的明确信息


请参阅此线程中的,以了解每个线程背后的优秀推理

隐式定义是将接口所需的方法/属性等作为公共方法直接添加到类中

显式定义强制仅当您直接使用接口而不是底层实现时才公开成员。在大多数情况下,这是首选

  • 通过直接使用界面,您没有确认, 以及将代码耦合到底层实现
  • 如果您已经拥有(比如)公共财产名称 您希望实现一个接口,该接口也具有 Name属性,显式执行此操作将使两者分开。即使 如果他们在做同样的事情,我仍然会委托他们 调用Name属性。你永远不知道,你可能想要改变 Name如何为普通类工作,以及Name如何为接口工作 物业日后开始运作
  • 如果隐式实现接口,则类现在公开 可能仅与客户相关的新行为 接口,这意味着您没有保持类简洁 够了(我的意见)

  • 如果显式实现,则只能通过接口类型的引用引用接口成员。作为实现类类型的引用不会公开这些接口成员

    如果您的实现类不是公共的,除了用于创建类的方法(可以是工厂或容器)和接口方法(当然),那么我认为显式实现接口没有任何好处

    否则,显式实现接口会确保不使用对具体实现类的引用,从而允许您在以后更改该实现。我想,“确保”是“优势”。一个功能完善的实现可以在没有显式实现的情况下实现这一点

    在我看来,缺点是您会发现自己在实现代码中向/从接口强制转换类型,而实现代码确实可以访问非公共成员


    与许多事情一样,优势是劣势(反之亦然)。显式实现接口将确保不公开具体的类实现代码

    除了已经提供的非常好的答案外,在某些情况下,编译器需要显式实现才能确定需要什么。请看一下
    IEnumerable
    ,这是一个可能经常出现的主要示例

    下面是一个例子:

    public abstract class StringList : IEnumerable<string>
    {
        private string[] _list = new string[] {"foo", "bar", "baz"};
    
        // ...
    
        #region IEnumerable<string> Members
        public IEnumerator<string> GetEnumerator()
        {
            foreach (string s in _list)
            { yield return s; }
        }
        #endregion
    
        #region IEnumerable Members
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
        #endregion
    }
    

    PS:IEnumerable显式定义中的一小段间接操作是有效的,因为在函数内部,编译器知道变量的实际类型是StringList,这就是它解析函数调用的方式。实现某些抽象层的一个很好的小事实一些.NET核心接口似乎已经积累起来了。

    除了已经说明的其他原因外,这是一个类正在实现两个不同的接口,它们具有相同名称和签名的属性/方法

    /// <summary>
    /// This is a Book
    /// </summary>
    interface IBook
    {
        string Title { get; }
        string ISBN { get; }
    }
    
    /// <summary>
    /// This is a Person
    /// </summary>
    interface IPerson
    {
        string Title { get; }
        string Forename { get; }
        string Surname { get; }
    }
    
    /// <summary>
    /// This is some freaky book-person.
    /// </summary>
    class Class1 : IBook, IPerson
    {
        /// <summary>
        /// This method is shared by both Book and Person
        /// </summary>
        public string Title
        {
            get
            {
                string personTitle = "Mr";
                string bookTitle = "The Hitchhikers Guide to the Galaxy";
    
                // What do we do here?
                return null;
            }
        }
    
        #region IPerson Members
    
        public string Forename
        {
            get { return "Lee"; }
        }
    
        public string Surname
        {
            get { return "Oades"; }
        }
    
        #endregion
    
        #region IBook Members
    
        public string ISBN
        {
            get { return "1-904048-46-3"; }
        }
    
        #endregion
    }
    
    请注意,显式接口定义被推断为公共的,因此不能显式地将它们声明为公共的(或以其他方式)

    还请注意,您仍然可以拥有“共享”版本(如上所示),但尽管这是可能的,但此类属性的存在是值得怀疑的。也许它可以用作Title的默认实现,这样就不必修改现有代码来将Class1强制转换为IBook或IPerson

    如果不定义“共享”(隐式)标题,Class1的使用者必须先将Class1的实例显式强制转换为IBook或IPerson,否则代码将无法编译。

    Reason#1 当我不鼓励“编程到实现”(programming to a implementation)时,我倾向于使用显式接口实现

    例如,在基于web的应用程序中:

    public interface INavigator {
        void Redirect(string url);
    }
    
    public sealed class StandardNavigator : INavigator {
        void INavigator.Redirect(string url) {
            Response.Redirect(url);
        }
    }
    
    现在,另一个类(如a)不太可能依赖于StandardNavigator实现,而更可能依赖于INavigator接口(因为实现需要转换到接口以使用重定向方法)

    原因#2 我使用显式接口实现的另一个原因是将类的“默认值”保留在
    string IBook.Title
    {
        get
        {
            return "The Hitchhikers Guide to the Galaxy";
        }
    }
    
    string IPerson.Title
    {
        get
        {
            return "Mr";
        }
    }
    
    public string Title
    {
        get { return "Still shared"; }
    }
    
    public interface INavigator {
        void Redirect(string url);
    }
    
    public sealed class StandardNavigator : INavigator {
        void INavigator.Redirect(string url) {
            Response.Redirect(url);
        }
    }
    
    public sealed class CustomerComboBox : ComboBox, ICustomerComboBox {
        private readonly CustomerComboBoxPresenter presenter;
    
        public CustomerComboBox() {
            presenter = new CustomerComboBoxPresenter(this);
        }
    
        protected override void OnLoad() {
            if (!Page.IsPostBack) presenter.HandleFirstLoad();
        }
    
        // Primary interface used by web page developers
        public Guid ClientId {
            get { return new Guid(SelectedItem.Value); }
            set { SelectedItem.Value = value.ToString(); }
        }
    
        // "Hidden" interface used by presenter
        IEnumerable<CustomerDto> ICustomerComboBox.DataSource { set; }
    }
    
    interface I1
    {
        void implicitExample();
    }
    
    interface I2
    {
        void explicitExample();
    }
    
    
    class C : I1, I2
    {
        void implicitExample()
        {
            Console.WriteLine("I1.implicitExample()");
        }
    
    
        void I2.explicitExample()
        {
            Console.WriteLine("I2.explicitExample()");
        }
    }
    
    Public Overridable Function Foo() As Integer Implements IFoo.Foo
    
    Protected Overridable Function IFoo_Foo() As Integer Implements IFoo.Foo
    
    int IFoo.Foo() { return IFoo_Foo(); }
    protected virtual int IFoo_Foo() { ... real code goes here ... }
    
    // Given:
    internal interface I { void M(); }
    
    // Then explicit implementation correctly observes encapsulation of I:
    // Both ((I)CExplicit).M and CExplicit.M are accessible only internally.
    public class CExplicit: I { void I.M() { } }
    
    // However, implicit implementation breaks encapsulation of I, because
    // ((I)CImplicit).M is only accessible internally, while CImplicit.M is accessible publicly.
    public class CImplicit: I { public void M() { } }