简体   繁体   中英

Is there a C# equivalent of Java's @Override?

This has been asked before, but I could not get clarity from that answer, that's why I ask again...

Let's use two examples:

  1. class implements interface
  2. class extends an abstract class

My feeling is that with respect to the override keyword, both samples must behave identically. What is the desired goal of override ? To prevent a method being dropped in a superclass or interface without being changed in all subclasses or implementing classes. So a compile time code consistency check.

In this C# code, compiling results in error: '....RepositoryContext.getXmlDoc()': no suitable method found to override:

interface IRepositoryContext
{
    XmlDocument getXmlDoc();
}

class RepositoryContext : IRepositoryContext
{
     private readonly XmlDocument gXmlDoc = new XmlDocument();

     public override XmlDocument getXmlDoc() // does not compile
     {    
        return gXmlDoc;
     }
}

Whereas in this C# code, compilation works without any errors or warnings:

abstract class RepositoryContextBase
{

     public abstract XmlDocument getXmlDoc();
}

class RepositoryContext : RepositoryContextBase
{
     private readonly XmlDocument gXmlDoc = new XmlDocument();

     public override XmlDocument getXmlDoc()
     {    
        return gXmlDoc;
     }
}

Is it a valid assumption that this should not work identically, or is there a way around this, or...?

The override modifier is defined thus:

The override modifier is required to extend or modify the abstract or virtual implementation of an inherited method, property, indexer, or event.

http://msdn.microsoft.com/en-us/library/ebca9ah3.aspx

The override keyword specifies that the method overrides an existing method implementation, which is why you don't need to specify it when you're implementing an interface directly - there is no such method to override; you're the first to implement it.

When you use the override keyword, you're essentially saying "for this class, call this method instead of the base method." This obviously doesn't apply when there is no such base method (eg when you are directly implementing an interface).

For virtual or abstract methods from classes, you need to insert the override keyword or it won't work at all.

For interfaces, there is no equivalent.

However, interface implementations must implement all of their base methods, so forgetting a method will usually give you a compiler error.
This makes it less important.

In the first example it's an interface you're implementing. You can't override something when you're the only implementer in the inheritance chain.

In the second example you've inherited from a concrete implementation and stated that you want to implement the abstract member and the syntax for that (albeit not literally an override as much as an implementation ) is the override keyword. However, you are in fact overriding the chain you're a part of because you're implementing it.

So think of the override keyword more in relation to the fact that you're ensuring your implementation gets called instead of the base class when it's called on an instance of the inheritor.

This too explains why you must explicitly call base.Member() inside the override because you've overriden the chain.

Another OO concept to remember is that the same effect can be achieve on methods that aren't abstract or virtual . Members can in fact be hidden and you don't have to specify them with the new keyword.

With that being said it should help abstract for you the idea that these are very much just language features or maybe better said it's just syntax.

In your first example you are implementing an interface. In this case you do not have to specify the override keyword, simply remove it.

Seems like you have a misconception regarding interface implementation vs. inheritance .

  • Interface implementations are completely different from inheritance. With an interface, you statically (ie at compile time) enforce the presence of certain method signatures. Therefore, any keywords like override or the like are just plain wrong in such a context.
  • Inheritance on the contrary is causing runtime polymorphism through a virtual method table (basically a list of method adresses).

You can see this also from the fact that, in C#, you can implement as many interfaces as you like, whereas multiple inheritance is forbidden.

The reason is that there is a fundamental difference between implementing an interface and overriding a method .

In order to fully implement an interface, you have to provide implementations for all of methods and/or properties but those implementations do not necessarily have to be overrideable in turn. The compiler wants you to be very specific about your intentions when you create a method, because you may have one of a range of behaviours in mind, and it wants to be sure which one you mean.

The override keyword means "I am overriding the base class' implementation with this one". If when implementing an interface, there is no base implementation, then it doesn't apply. You use virtual to indicate an overrideable method with no base implementation, and omit both override and virtual otherwise.

So given this interface:

interface IFoo
{
    void Bar();
}

This class implements that interface, and permits classes to inherit from it in turn and override that implementation (since unlike in eg Java, methods in C# are not virtual by default):

class Foo : IFoo
{
    public virtual void Bar() { ... } // compiles
}

class DerivedFoo : Foo
{
    public override void Bar() { ... } // compiles, and may choose to call base.Bar()
}

Whereas this class implements that interface, and does not permit overrides:

class Foo : IFoo
{
    public void Bar(); // compiles
}

class DerivedFoo : Foo
{
    public override void Bar() { ... } // does NOT compile; Foo.Bar() is not virtual (overrideable)
}

There are in fact more possiblities than that, including:

  • You can create an abstract base class which implements an interface, but only provide abstract implementations for some/all methods.
  • You can explicitly implement an interface method
  • You can seal an overriding method to prevent further overrides
  • You can create a new method with the same name which is unrelated to the base class' method of that name

There are more details on MSDN .

If you aren't specific enough for the compiler, it will warn you or throw an error.

Update

The reason the compiler complains in the second example above, is that you will not get polymorphic behaviour. That is, if someone has a reference to Foo and calls Bar() , they will get Foo 's implementation, not DerivedFoo 's. This is because Bar.Foo is not in the virtual method table. Put another way, in C#, the default when compared to Java is that all methods are final unless you say otherwise.

From your comments it sounds like you're trying to get a warning or error in the case where, in my first example above, you then change IFoo by removing the Bar method entirely. (Obviously if you just change the method signature, you'll get a suitable compile error as you'd hope.)

You can achieve this by explicitly implementing the method:

class Foo : IFoo
{
    void IFoo.Bar() { ... }
}

Then if the interface changes, you will get a compile error. However, this means derived classes can no longer override Foo's implementation; if you want that behaviour as well, you need:

class Foo : IFoo
{
    void IFoo.Bar() { ... }

    protected /* or public */ virtual void Bar()
    {
        IFoo foo = this; // declare rather than cast, to get compile error not runtime exception
        foo.Bar();
    }
}

You will still get compile errors if you remove the method, both from your explicit and other implementation.

Bear in mind that the explicit implementation is only available to callers with a reference to an IFoo, not a Foo. But if as in the above code you do add a public method which, for example, delegates to the explicit IFoo implementation, that won't be a problem (and it doesn't have to be virtual unless you want it overrideable).

This is an approach that works; whether it's overkill is a matter of taste, but I can see the merit in removing redundant code as part of refactoring, provided the classes are not public and/or not used outside your assembly. However instead of factoring code in this fashion I'd recommend using a tool such as ReSharper which will warn you about unused methods.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM