Is there something comparable to explicit interface implementation but for classes instead in C#?
Consider the following situation:
Company X provides a library containing a class as follows:
public class LibraryClass
{
public virtual void A() { }
public void DoWork()
{
// does something
}
}
Company Y uses this library in one of its products and inherits from LibraryClass
:
public class UserClass : LibraryClas开发者_StackOverflows
{
public virtual void B() { }
}
So far everything works fine. But at someday X releases a new library version and adds a virtual method B()
to LibraryClass
:
public class LibraryClass
{
public virtual void A() { }
public virtual void B() { }
public void DoWork()
{
// does something
// now uses B with certain semantic assumptions
}
}
Now Y updates to the new library version. While compiling with a reference to the new version, the compiler emits a warning saying that UserClass.B()
is hiding the inherited method LibraryClass.B()
and therefore should either specify the new
keyword or override the method. Because there is a semantic gap between the existing method UserClass.B()
and the newly introduced method LibraryClass.B()
Y decides to introduce the new
keyword because any existing override of UserClass.B()
will probably not provide the semantics expected by DoWork()
which would break the code. On the other hand Y wants to use a new feature of the library which would require an override of LibraryClass.B()
. Now this is not possible: If the override would be done in a derived class of UserClass
the override would refer to UserClass.B()
due to the new
keyword; an override of B
in UserClass
itself is not even allowed as it already defines a public method with that signature.
This situation could be solved if there was either a way in a derived class of UserClass
to specify that the override refers to LibraryClass.B()
which is not possible as far as I know -or- if B()
could be explicitly overriden in 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();
}
...
}
Is there any way in the language to solve this situation other than renaming the original B()
in UserClass
(which might not even be possible if it was part of a library itself which is consumed by company Z)? If not, is this a C# limitation or a limitation of the CLR?
Sorry for the long post and thank you for reading up to this point.
Edit: This is not a CLR limitation. C++/CLI supports named overrides which solve the situation, so you could do something like virtual void LibraryB(void) = LibraryClass::B;
. The C# design team probably just missed this issue.
Is there any way in the language to solve this situation other than...
No, there isn't. If you genuinely feel that this is a risk, perhaps use an interface-based design rather than inheritance. Personally, I feel it unlikely that this is going to cause you any significant issue, especially if you use more specific method names than B()
.
If you wanted the new method B
in LibraryClass
to be available to classes that derived from UserClass
, you could write a method in UserClass
like this:
public virtual void BNew()
{
return (this as LibraryClass).B();
}
You can't have the exact behaviour as explicit interface implementation.
The closest you can get, is by using method hiding, using the new
keyword.
Given these classes,
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");
}
}
This will give you this behaviour:
C1 test = new C2 ();
test.B ();
C2 test2 = new C2 ();
test2.B ();
Output:
C1 - B
C2 - B
As long as we are talking about changing the method signature in UserClass to be 'new' we can talk about changing the method name. So I don't see a big problem here, only a click on autorename in VS. If autorename is not enough since you are using these classes in other assemblies not in the solution, you are probably missing something in the design (ie. interfaces).
This problem is:
- very rare
- easily solvable
If it is not then:
- you have bad design
In a way, both X and Y are to blame: X for creating an inheritable class that wasn't designed for inheritance and for extending such a class, and Y for making a class that derives from such a class. Neither X nor Y can predict how the other will expand on their respective code in the future. Using interfaces (on X's part) or using a wrapper class (on Y's part) would have been less painful in the long run.
精彩评论