Interface inheritance: is extending properties possible?
I want to do this:
interface IBase
{
string Property1 { ge开发者_高级运维t; }
}
interface IInherited : IBase
{
string Property1 { get; set; }
}
So that IInherited
would have the inherited property Property1
with added functionality to allow set
.
Is that possible? What's the syntax?
EDIT: please notice I put the word "inherited" in bold face. I am asking specifically about inheriting the property, not hiding it behind a new one.
If the fact that the only way to do this is by using the new
keyword bothers you, then in my opinion you're thinking about interfaces wrong.
Sure, you could say that IInherited
"inherits from" IBase
; but what does that really mean? These are interfaces; they establish code contracts. By hiding the IBase.Property1
property with new string Property1 { get; set; }
, you are not shadowing any functionality. Thus the traditional reason that a lot of developers consider hiding to be a "bad" thing -- that it violates polymorphism -- is irrelevant in this case.
Ask yourself: what really matters when it comes to interfaces? They provide a guarantee of responding to certain method calls, right?
So, given the following two interfaces:
interface IBase
{
string Property1 { get; }
}
interface IInherited : IBase
{
new string Property1 { set; }
}
- If an object implements
IBase
, you can read itsProperty1
property. - If an object implements
IInherited
, you can read itsProperty1
property (just as with anIBase
implementation), and you can also write to it.
Again, there's really nothing problematic here.
Hiding a member is violating the Liskov Substitution Principle and pretty much just shouldn't be done, ever. By hiding this member you are introducing a very difficult to locate bug since 2 different outcomes will occur depending whether you cast the object as ((IInherited).Property1)
or cast it to ((IBase).Property1)
.
http://en.wikipedia.org/wiki/Liskov_substitution_principle
Your code should work anyway... it just creates a complier warning because of hiding Property1. To clear this warning mark Property1 in IInherited with the new prefix
Not explicitly, no. You have two options:
public interface IBase
{
string Property1 { get; }
}
public interface IInherited : IBase
{
void SetProperty1(string value);
}
Or you can just kill the compiler warning with the new
keyword:
public interface IBase
{
string Property1 { get; }
}
public interface IInherited : IBase
{
new string Property1 { get; set; }
}
Unless you implement IInherited.Property1
explicitly, IBase
will bind to your settable implementation automatically.
Unfortunately not - properties cannot be extended as such. However, you can just hide the property by using new:
interface IInherited : IBase
{
// The new is actually unnecessary (you get warnings though), hiding is automatic
new string Property1 { get; set; }
}
Or, you can make your own getter and setter methods which can be overriden (good 'ol Java style):
interface IBase
{
string GetProperty1();
}
interface IInherited : IBase
{
void SetProperty1(string str);
}
Properties are actually converted to getter and setter methods by the compiler.
You can either mark the property with the "new" keyword, or you can skip the inheritance:
public interface IBase
{
string Property1 { get; }
}
public interface IInherited : IBase
{
new string Property1 { get; set; }
}
Or:
public interface IBase
{
string Property1 { get; }
}
public interface IInherited
{
string Property1 { get; set; }
}
Either way, this should work:
public class SomeClass : IInherited, IBase
{
public string Property1
{
get
{
// ...
}
set
{
// ...
}
}
}
You may want to think hard before you make an inheritance chain for your interfaces, though. Who is going to see which interface? Would you need to cast to IInherited when passed an IBase? If so, can you be guaranteed that you can do that cast (if you allow user created classes, then the answer is no)? This kind of inheritance can really hurt (re)usability if you're not careful.
I had this conversation with a couple of our Lead Devs at my work, and the conclusion that we came to is that:
- Either way technically works.
- Interfaces are all about singular purpose.
An Interface is used to define a way that any inheriting class can act. Even if your second interface shares pieces, or is even used in some of the same conditions, an interface is defined to explain how to use a class in ALL conditions related to that interface.
Additionally, classes are able to inherit multiple interfaces for this very reason. In terms of code clarity:
public class SomeClass : IInherited, IBase
The line above explicity states that SomeClass is capable of doing the actions of IInherited, and the actions of IBase, and it does not matter that some of those actions are the same. Having to crawl backwards through the interfaces to discover that IInherited extends IBase could be confusing to other developers that may look at your code in the future.
It may seem like a duplication of effort having the same values in both interfaces, but there are no assumptions made in the function of your code.
精彩评论