出于隐藏成员的唯一目的而使用显式接口实现的充分理由是什么?


11

在对C#的复杂性进行的一项研究中,我遇到了有关显式接口实现的有趣文章。

While this syntax is quite helpful when you need to resolve name clashes, you can use explicit interface implementation simply to hide more "advanced" members from the object level.

对我没有经验的眼睛来说,允许使用object.method()或要求强制转换之间的区别((Interface)object).method()似乎是卑鄙的迷惑。文中指出,这将隐藏智能感知对象级别的方法,但为什么你会这样做,如果没有必要,以避免名称冲突?


Answers:


12

想象一下这样一种情况,一个接口强迫一个类实现一些实际上并不属于该类的方法。当接口特别大并且违反接口隔离原则时,通常会发生这种情况。

该类需要实现该接口,但是您可以显式实现那些您不想明显使用的方法,而不是用没有意义的方法来污染其高度可见的公共接口。该类的高度可见的公共接口是您希望如何使用该类的方式,当通过该接口访问该类时,便可以使用显式实现。


6
仅仅是我,还是听起来像一个可怕的主意?
凯文·佩诺

5
@Kevin,怎么回事?有时,接口超出了您的控制范围,您必须使用它。减轻霸道界面的损害似乎是合理的。
克里斯·皮特曼

1
+1指出现实世界很多时候都妨碍正确的做事方式。@Kevin是的,这是一个糟糕的主意,但有时您别无选择,不得不与斜坡一起工作-最好将其隐藏起来,并在无法真正正确地做事时做好做事的门面。
韦恩·莫利纳

@Wayne,我了解您想要/使用这种系统的原因。地狱,在您陈述的情况下,我可能会用它。我想我的简短评论实际上只是指出这是不适当的,所以为什么要允许使用该语言。
凯文·佩诺

1
过度的界面分离可能是构成和聚集的主要障碍。例如,考虑一个人希望有一个实现IEnumerable<T>可以像其他两个实现一样。如果IEnumerable<T>包含一个属性以说明其计数是已知的,可能是无限的还是不知道的,以及一种询问其计数是什么的方法,则在多个IEnumerable<T>变量合在一起并充当串联的情况下,此类可以有效地报告其计数封装的集合知道它们的数量。
超级猫

4

我发现最有用的应用程序是实施工厂。在许多情况下,创建在工厂内部可变但对外部类不可变的类很有用。可以通过使用内部类在Java中轻松实现此目的,方法是将字段及其设置器设为私有,并且仅将获取器公开为公共成员。但是,在C#中,我必须使用显式接口来实现相同的目的。我将进一步说明:

在Java中,内部类和外部类可以访问彼此的私有成员,这是很有意义的,因为这些类之间的关系非常紧密。它们在同一代码文件中,可能由同一开发人员开发。这意味着内部类中的私有字段和方法仍可以由工厂访问以修改其值。但是,外部类只能通过其公共获取程序来访问这些字段。

但是,在C#中,外部类无法访问内部类的私有成员,因此该概念不能直接应用。通过在外部类中定义一个私有接口并在内部类中显式实现它,我将显式接口用作解决方法。这样,只有外部类可以像在Java中一样访问此接口中的方法(但它们必须是方法,而不是字段)。

例:

public class Factory
{
    // factory method to create a hard-coded Mazda Tribute car.
    public static Car CreateCar()
    {
        Car car = new Car();

        // the Factory class can modify the model because it has access to
        // the private ICarSetters interface
        ((ICarSetters)car).model = "Mazda Tribute";

        return car;
    }

    // define a private interface containing the setters.
    private interface ICarSetters
    {
        // define the setter in the private interface
        string model { set; }
    }

    // This is the inner class. It has a member "model" that should not be modified
    // but clients, but should be modified by the factory.
    public class Car: ICarSetters
    {
        // explicitly implement the setter
        string ICarSetters.model { set; }

        // create a public getter
        public string model { get; }
    }
}

class Client
{
    public Client()
    {
        Factory.Car car = Factory.CreateCar();

        // can only read model because only the getter is public
        // and ICarSetters is private to Factory
        string model = car.model;
    }
}

那就是我要使用显式接口的目的。


3

如果一个类实现的两个接口包含一个具有相同签名的成员,则在类上实现该成员将导致两个接口都使用该成员作为其实现。在下面的示例中,所有调用均Paint调用同一方法。C#

class Test 
{
    static void Main()

    {
        SampleClass sc = new SampleClass();
        IControl ctrl = (IControl)sc;
        ISurface srfc = (ISurface)sc;

        // The following lines all call the same method.
        sc.Paint();
        ctrl.Paint();
        srfc.Paint();
    }
}


interface IControl
{
    void Paint();
}
interface ISurface
{
    void Paint();
}
class SampleClass : IControl, ISurface
{
    // Both ISurface.Paint and IControl.Paint call this method. 
    public void Paint()
    {
        Console.WriteLine("Paint method in SampleClass");
    }
}

相反,显式实现其中一个(或两个)可以使您为每个指定不同的行为。


1

当一个对象具有两种或多种非常不同的通信形式时,显式接口非常方便。

例如,一个对象维护需要与父对象通信的子对象的集合。

有些操作我们只希望外部调用者可以访问,而有些操作我们只希望子对象可以访问。

显式接口有助于确保这种划分。

    static void Main(string[] args)
    {
        var parent = new Parent();
        parent.DoExternalStuff();
    }

    interface IExternal {
        void DoExternalStuff();
    }

    interface IInternal {
        void DoInternalStuff();
    }

    class Parent : IExternal, IInternal
    {
        public Parent()
        {
            var child = new Child(this);
        }

        public void DoExternalStuff()
        {
           // do something exciting here for external callers
        }

        void IInternal.DoInternalStuff()
        {
            // do something exciting here for internal callers
        }
    }

    class Child
    {
        public Child(IInternal parent)
        {
            parent.DoInternalStuff();
        }
    }

0

也许,如果您具有对用户有用的功能,但前提是您确实知道自己在做什么(足以阅读有关功能的文档),但是如果您不这样做,那很可能会破坏事情。

为什么您会这么做而不是提供,我不知道第二个“高级功能界面”。


0

通常,对代码的读取要比对代码的读取要多,我只使用Intellisense来快速编写代码。我不会以使Intellisense更好的方式编写代码。

我不怎么看

((Interface)object).method()比object.method()更具可读性。

如果我在特定对象上有很多方法,我可能会质疑它是否是上帝对象,实际上应该分解为多个更简单的对象。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.