是否有类似于显式接口实现的东西,但对于C#中的类而言?
考虑以下情况:
公司X提供了一个包含类的库,如下所示:
public class LibraryClass
{
public virtual void A() { }
public void DoWork()
{
// does something
}
}
Y公司在其中一个产品中使用此库,并继承自LibraryClass
:
public class UserClass : LibraryClass
{
public virtual void B() { }
}
到目前为止一切正常。但是有一天X发布了一个新的库版本并向B()
添加了一个虚拟方法LibraryClass
:
public class LibraryClass
{
public virtual void A() { }
public virtual void B() { }
public void DoWork()
{
// does something
// now uses B with certain semantic assumptions
}
}
现在Y更新了新的库版本。在使用对新版本的引用进行编译时,编译器会发出警告,指出UserClass.B()
隐藏了继承的方法LibraryClass.B()
,因此应该指定new
关键字或覆盖该方法。由于现有方法UserClass.B()
与新引入的方法LibraryClass.B()
之间存在语义差距,因此Y决定引入new
关键字,因为任何现有的UserClass.B()
覆盖都可能无法提供DoWork()
期望的语义会破坏代码。另一方面,Y想要使用库的新功能,这需要覆盖LibraryClass.B()
。现在这是不可能的:如果覆盖将在UserClass
的派生类中完成,则由于UserClass.B()
关键字,覆盖将引用new
;甚至不允许在B
中覆盖UserClass
,因为它已经定义了具有该签名的公共方法。
如果在UserClass
的派生类中有一种方法指定覆盖引用LibraryClass.B()
这种情况可以解决,据我所知,这是不可能的 - 或 - 如果{可以在B()
中明确覆盖{1}}:
UserClass
除了重命名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();
}
...
}
中的原始B()
之外,语言中是否有任何方法可以解决这种情况(如果它是公司消耗的库本身的一部分,甚至可能不可能) Z)?如果不是,这是C#限制还是CLR的限制?
对于这篇长篇文章感到抱歉,感谢您阅读这一点。
修改:这不是CLR限制。 C ++ / CLI支持解决这种情况的命名覆盖,因此您可以执行UserClass
之类的操作。 C#设计团队可能只是错过了这个问题。
答案 0 :(得分:4)
除了......之外,语言中是否有任何方法可以解决这种情况?
不,没有。如果您真的感觉这是一种风险,也许使用基于接口的设计而不是继承。就个人而言,我觉得这不太可能导致任何重大问题,特别是如果您使用比B()
更具体的方法名称。
答案 1 :(得分:1)
如果您希望B
中的新方法LibraryClass
可用于从UserClass
派生的类,您可以在UserClass
中编写一个方法,如下所示:
public virtual void BNew()
{
return (this as LibraryClass).B();
}
答案 2 :(得分:0)
您不能具有显式接口实现的确切行为。
您可以获得的最接近的方法是使用方法隐藏,使用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
答案 3 :(得分:0)
只要我们谈论将UserClass中的方法签名更改为“&new;'我们可以谈谈改变方法名称。所以我不会在这里看到一个大问题,只需点击VS中的自动名称。如果autorename不够,因为您在其他程序集中使用这些类而不在解决方案中,那么您可能在设计中缺少某些东西(即接口)。
这个问题是:
如果不是那样:
答案 4 :(得分:-1)
在某种程度上,X和Y都应该归咎于:X用于创建一个可继承的类,它不是为继承而设计的,用于扩展这样的类,而Y用于创建一个派生自这样一个类的类。 X和Y都不能预测对方将来如何扩展其各自的代码。从长远来看,使用接口(在X的部分)或使用包装类(在Y的部分)可能不那么痛苦。