Interface inheritance: is extending properties possible?

后端 未结 7 1192
庸人自扰
庸人自扰 2021-02-03 23:32

I want to do this:

interface IBase
{
    string Property1 { get; }
}

interface IInherited : IBase
{
    string Property1 { get; set; }
}

So th

相关标签:
7条回答
  • 2021-02-03 23:51

    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.

    0 讨论(0)
  • 2021-02-04 00:05

    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

    0 讨论(0)
  • 2021-02-04 00:05

    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.

    0 讨论(0)
  • 2021-02-04 00:05

    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.

    0 讨论(0)
  • 2021-02-04 00:06

    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.

    0 讨论(0)
  • 2021-02-04 00:10

    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.

    0 讨论(0)
提交回复
热议问题