views:

136

answers:

6

I want to do this:

interface IBase
{
    string Property1 { get; }
}

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.

+1  A: 

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

James Gaunt
A: 

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.

Merlyn Morgan-Graham
+1  A: 

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.

Adam Robinson
On the implementation there is only 1 property called Property1. If you access the implementation via a reference to IInherited you can call getter and setter, and if you access it via IBase you can only call the getter. But this is the required behaviour isn't it?
James Gaunt
Yes, that's what I want. But I'll probably have to go with getter/setter methods, since it seems this can't be done...
Malki
It can be done, exactly as you are doing it... are you getting a compiler error? What is the error?
James Gaunt
It compiles fine. But I still want the inheritance in there. getter/setter methods aren't the worst idea ever, I just wanted to use properties for readability.
Malki
@Malki: Again, there is *no such thing as inheritance* when it comes to interfaces. It's more of...addition. You're using inheritance syntax, but it is not, strictly speaking, inheritance. Just do it the way you have it and use `new`.
Adam Robinson
+1  A: 

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.

Callum Rogers
A: 

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 IBase1 or cast it to IBase.

http://en.wikipedia.org/wiki/Liskov_substitution_principle

Chris Marisic
-1. This is not hiding in the traditional sense, since interfaces do not support polymorphism anyway.
Adam Robinson
@Chris, Adam: I think Chris is correct, IFF we place his comment in the context of explicitly implemented interfaces, with different implementations.
Merlyn Morgan-Graham
A class that implements IInherited could be casted as a IBase with lesser rights to modify it, it is not overriding the implementation of a method, as the getter will return the same (as the two interfaces 'share' the getter implementation)
Diego Pereyra
@Diego, Chris: The getter can have multiple implementations if you implement it explicitly. You could end up with a hard to find bug if a base class you inherit from (that implements one of these interfaces) does explicit implementation. However, Chris, I recommend you delete this since it is attracting downvotes from people who don't know any better =P
Merlyn Morgan-Graham
The importance of having the LSP explanation in the thread is worth the trivial amounts of points I might lose from a couple of DVs, besides the upvotes I've gotten would offset many more DVs.
Chris Marisic
+4  A: 

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; }
}
  1. If an object implements IBase, you can read its Property1 property.
  2. If an object implements IInherited, you can read its Property1 property (just as with an IBase implementation), and you can also write to it.

Again, there's really nothing problematic here.

Dan Tao
I stand corrected. Thanks for the lesson :)
Malki
You are correct, except in cases of explicit implementation. You can have different implementations for each version, hence it is still hiding. There is a potential that someone implementing your interface could do this, either accidentally or on purpose, so you should be careful how you consume these interfaces. If you want to avoid this problem, and still use inheritance, then use "new", but don't add a second getter.
Merlyn Morgan-Graham
@Merlyn, agreed. By removing the 2nd get statement this would no longer violate the LSP.
Chris Marisic
Your code declares two *different* getters for the property. In `IInherited` you probably want to declare only `new string Property1 { set; }`. A class that implements `IInherited` can have a property with a getter and a setter and it will implement both interfaces.
Timwi
@Merlyn, @Chris, and @Timwi: Good call, you guys. I will update the answer.
Dan Tao