C# C语言中类的显式接口实现#

C# C语言中类的显式接口实现#,c#,C#,除了C#中的类之外,还有什么可以与显式接口实现相比的吗 考虑以下情况: 公司X提供了一个包含类的库,如下所示: public class LibraryClass { public virtual void A() { } public void DoWork() { // does something } } Y公司在其产品中使用此库,并继承自LibraryClass: public class UserClass : LibraryClas

除了C#中的类之外,还有什么可以与显式接口实现相比的吗

考虑以下情况:

公司X提供了一个包含类的库,如下所示:

public class LibraryClass
{
    public virtual void A() { }

    public void DoWork()
    {
        // does something
    }
}
Y公司在其产品中使用此库,并继承自
LibraryClass

public class UserClass : LibraryClass
{
    public virtual void B() { }
}
public class LibraryClass
{
    public virtual void A() { }
    public virtual void B() { }

    public void DoWork()
    {
        // does something
        // now uses B with certain semantic assumptions
    }
}
public class UserClass : LibraryClass
{
    ...

    // Override this method in order to change the behavior of LibraryClass.B()
    public virtual void LibraryB() { }

    private void override LibraryClass.B()
    {
        LibraryB();
    }

    ...
}
到目前为止一切正常。但总有一天X会发布一个新的库版本,并将一个虚拟方法
B()
添加到
LibraryClass

public class UserClass : LibraryClass
{
    public virtual void B() { }
}
public class LibraryClass
{
    public virtual void A() { }
    public virtual void B() { }

    public void DoWork()
    {
        // does something
        // now uses B with certain semantic assumptions
    }
}
public class UserClass : LibraryClass
{
    ...

    // Override this method in order to change the behavior of LibraryClass.B()
    public virtual void LibraryB() { }

    private void override LibraryClass.B()
    {
        LibraryB();
    }

    ...
}
现在Y更新到新的库版本。在引用新版本进行编译时,编译器会发出警告,指出
UserClass.B()
正在隐藏继承的方法
LibraryClass.B()
,因此应该指定
new
关键字或重写该方法。因为现有方法
UserClass.B()
和新引入的方法
LibraryClass.B()
Y之间存在语义差距,所以Y决定引入
new
关键字,因为对
UserClass.B()
的任何现有重写可能不会提供
DoWork()所期望的语义
这会破坏代码。另一方面,Y希望使用库的一个新功能,它需要重写
LibraryClass.B()
。现在这是不可能的:如果覆盖将在
UserClass
的派生类中执行,则由于
new
关键字,覆盖将引用
UserClass.B()
;甚至不允许在
UserClass
本身中重写
B
,因为它已经用该签名定义了一个公共方法

如果在
UserClass
的派生类中有一种方法指定重写引用
LibraryClass.B()
,就我所知,这是不可能的,或者如果
B()
可以在
UserClass
中显式重写:

public class UserClass : LibraryClass
{
    public virtual void B() { }
}
public class LibraryClass
{
    public virtual void A() { }
    public virtual void B() { }

    public void DoWork()
    {
        // does something
        // now uses B with certain semantic assumptions
    }
}
public class UserClass : LibraryClass
{
    ...

    // Override this method in order to change the behavior of LibraryClass.B()
    public virtual void LibraryB() { }

    private void override LibraryClass.B()
    {
        LibraryB();
    }

    ...
}
除了在
UserClass
中重命名原始的
B()
(如果它是Z公司使用的库本身的一部分,这甚至可能是不可能的)之外,该语言还有其他方法来解决这种情况吗?如果不是,这是C限制还是CLR限制

很抱歉发了这么长的帖子,感谢您阅读到这一点

编辑:这不是CLR限制。C++/CLI支持解决这种情况的命名重写,因此您可以执行类似于
virtualvoidlibraryb(void)=LibraryClass::B。C#design团队可能刚刚错过了这个问题

在语言中有什么方法可以解决这种情况,除了


不,没有。如果您真的觉得这是一种风险,那么可以使用基于接口的设计,而不是继承。就我个人而言,我觉得这不太可能给您带来任何重大问题,特别是如果您希望
LibraryClass
中的新方法
B
可用于从
UserClass
派生的类,那么您使用的方法名称比
B()更具体,您可以在
UserClass
中编写如下方法:

public virtual void BNew()
{
    return (this as LibraryClass).B();
}

您不能具有显式接口实现的确切行为。 最接近的方法是使用方法隐藏,使用
new
关键字

考虑到这些课程

    public class C1
    {
        public void A()
        {
            Console.WriteLine ("C1 - A");
        }
        public void B()
        {
            Console.WriteLine ("C1 - B");
        }
    }

    public class C2 : C1
    {
        public new void B()
        {
            Console.WriteLine ("C2 - B");
        }
    }
这将使您产生以下行为:

        C1 test = new C2 ();
        test.B ();

        C2 test2 = new C2 ();
        test2.B ();
输出:

C1 - B 
C2 - B

只要我们讨论将UserClass中的方法签名更改为“新”,我们就可以讨论更改方法名称。因此,我认为这里没有什么大问题,只需在VS中单击autorename。如果autorename不够,因为您在解决方案之外的其他程序集中使用这些类,那么您可能在设计中缺少了一些东西(即接口)

这个问题是:

  • 非常罕见
  • 易解
如果不是,则:

  • 你的设计很糟糕

在某种程度上,X和Y都是罪魁祸首:X创建了一个不是为继承而设计的可继承类并扩展了这样一个类,Y创建了一个从这样一个类派生的类。X和Y都无法预测另一个将如何在未来扩展各自的代码。从长远来看,使用接口(对于X而言)或使用包装类(对于Y而言)将不会那么痛苦。

我不认为这是CLR限制;使用TypeBuilder和IL Emit构造类型时,可以使用具有不同名称的方法指定MethodOverride。这通常用于实现显式接口重写,但我相信它将允许您从具有不同名称的基类映射方法重写。丹·布莱恩特:谢谢你的提示,我会试着检查一下。你可能是对的。但另一方面:名称冲突可能发生在层次结构中的某个地方,从一层到另一层,不能使用的名称加起来,可能不太可能有两个通用名称(例如添加、删除等),甚至可能
base.B()
就足够了,但我无法再重写该方法(调用该方法不是实际问题)同意。我意识到你所问的不仅仅是“我如何调用我用‘新’隐藏的方法?”.我的答案是根据我们不能改变语言本身这一事实而得出的。这是你提出的一个非常有趣的问题,即使它有点深奥。老实说,我是在一次关于语言设计的讲座后提出这个问题的(所以我不能完全相信这一点)讨论了给定的问题(尽管是以更一般的方式)。我只是想知道是否有一个C#解决这个我不知道的问题的方法。你说的基本上归结为“不要在你无法控制的类上使用继承”(据我所知).这可能是一个切实可行的答案