C# C语言中类的显式接口实现#
除了C#中的类之外,还有什么可以与显式接口实现相比的吗 考虑以下情况: 公司X提供了一个包含类的库,如下所示:C# C语言中类的显式接口实现#,c#,C#,除了C#中的类之外,还有什么可以与显式接口实现相比的吗 考虑以下情况: 公司X提供了一个包含类的库,如下所示: public class LibraryClass { public virtual void A() { } public void DoWork() { // does something } } Y公司在其产品中使用此库,并继承自LibraryClass: public class UserClass : LibraryClas
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#解决这个我不知道的问题的方法。你说的基本上归结为“不要在你无法控制的类上使用继承”(据我所知).这可能是一个切实可行的答案