3

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 : LibraryClass
{
    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.

2
  • I don't believe this is a CLR limitation; when constructing a Type using TypeBuilder and IL Emit, you can specify a MethodOverride with a method that has a different name. This is generally used to implement explicit interface overrides, but I believe it will allow you to map overrides of methods from a base class with a different name. I haven't actually tried it, mind you. Commented Jul 1, 2011 at 20:49
  • @Dan Bryant: Thank you for the hint, I will try and check that. Commented Jul 1, 2011 at 21:38

5 Answers 5

4

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().

Sign up to request clarification or add additional context in comments.

1 Comment

You might be right on this. But on the other hand: The name conflict could be somewhere in the hierarchy and from layer to layer the names which must not be used add up and it is probably not unlikely to have a common name twice (e.g. Add, Remove, ...)
1

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();
}

3 Comments

Probably even base.B() would suffice, but I could not override the method anymore (calling the method is not the actual problem)
Agreed. I realize that you're asking about something bigger than just "How can I call a method that I've hidden with 'new'?". My answer is pursuant to what might be the next best thing in light of the fact that we can't change the language itself. This is a really interesting issue that you've brought up, even if it is a bit on the esoteric side.
To be honest: I came up with this question after a lecture on language design (so I cannot take the credit for it all by myself) which discussed the given problem (though in a more general way). I just wondered whether there was a solution in C# for this problem which I didn't knew.
0

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

1 Comment

I am aware of that, but it doesn't solve the "can the original method be overriden" problem
0

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

1 Comment

As long as I own all three assemblies renaming might be a solution. But consider a 3rd-party framework (taking the role of Y) which inherits from a BCL (taking the role of X) class and a customer (Z) which inherits form that class in the 3rd-party framework. If the framework renames a method all customers (!) have to change the names to. Even worse: If the signature matches any overrides will be silently re-mapped to the wrong base class method causing unexpected behavior.
-1

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.

2 Comments

What you say basically boils down to "Do not use inheritance on classes which you do not control" (as I understand it). This might be a practical answer, but what if X is Microsoft, LibraryClass is System.Windows.Forms.Form, B is some method or property which Microsoft added in order to support a new Windows version. Now I'm pretty much screwed as not inheriting Form is not a solution.
What I meant was deriving from a class that wasn't designed for inheritance. System.Windows.Forms.Form is not an example of such a class, a class like System.Collections.Generic.List<T> would be a better example. I only assumed that LibraryClass was not a class that was designed for inheritance: we wouldn't know unless we looked at X's documentation for LibraryClass.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.