Can you use the C# new keyword to expand properties on an interface?

戏子无情 提交于 2019-12-09 12:06:44

问题


I understand how the "new" keyword can hide methods in a derived class. However, what implications does it have for classes that implement interfaces that use the keyword?

Consider this example, where I decide to expand an interface by making its properties read/write.

public interface IReadOnly {

   string Id {
      get;
   }
}

public interface ICanReadAndWrite : IReadOnly  {

   new string Id {
      get;
      set;
   }
}

Then you are able to do things like this:

public IReadOnly SomeMethod() {
   // return an instance of ICanReadAndWrite
}

Is this bad design? Will it cause issues for my classes that implement ICanReadAndWrite?

Edit: Here is a contrived example of why I might want to do something like this:

Say I have a factory class that returns an IShoppingCartItemReadWrite. I can then have a service layer that manipulates prices on it, changes stuff, etc. Then, I can pass these objects as IShoppingCartItemReadOnly to some kind of presentation layer that won't change them. (Yes, I know it technically can change them-- this is a design question, not security, etc.)


回答1:


It's not a particularly bad idea. You should be aware that the implementor can (if it implicitly implements the interface, then a single read/write property could satisfy both interfaces) provide two distinct implementations:

class Test : ICanReadAndWrite {
   public string Id {
      get { return "100"; }
      set { }
   }
   string IReadOnly.Id {
      get { return "10"; }
   }
}

Test t = new Test();
Console.WriteLine(t.Id);  // prints 100
Console.WriteLine(((IReadOnly)t).Id); // prints 10

By the way, in general, the new inheritance modifier does nothing except to tell the compiler to shut up and don't throw out a "you're hiding that member" warning. Omitting it will have no effect in the compiled code.




回答2:


You should not implement the ICanReadWrite based on IReadOnly, but instead make them separate.

ie. like this:

public interface IReadOnly
{
    string Id
    {
        get;
    }
}

public interface ICanReadAndWrite
{
    string Id
    {
        get;
        set;
    }
}

Here's a class using them:

public class SomeObject : IReadOnly, ICanReadWrite
{
    public string Id
    {
        get;
        set;
    }
}

Note that the same property in the class can support both interfaces.

Note that as per the comment, the only way to get a robust solution would be to also have a wrapper object.

In other words, this is not good:

public class SomeObject : IReadOnly, ICanReadWrite
{
    public string Id
    {
        get;
        set;
    }

    public IReadOnly AsReadOnly()
    {
        return this;
    }
}

as the caller can just do this:

ICanReadWrite rw = obj.AsReadOnly() as ICanReadWrite;
rw.Id = "123";

To get a robust solution, you need a wrapper object, like this:

public class SomeObject : IReadOnly, ICanReadWrite
{
    public string Id
    {
        get;
        set;
    }

    public IReadOnly AsReadOnly()
    {
        return new ReadOnly(this);
    }
}

public class ReadOnly : IReadOnly
{
    private IReadOnly _WrappedObject;

    public ReadOnly(IReadOnly wrappedObject)
    {
        _WrappedObject = wrappedObject;
    }

    public string Id
    {
        get { return _WrappedObject.Id; }
    }
}

This will work, and be robust, right up until the point where the caller uses reflection.




回答3:


This is perfectly legal and the implications for your class that implements the ICanReadAndWrite interface would simply be that when it is treated as an IReadOnly it can only read, but when treated as ICanReadAndWrite it would be able to do both.




回答4:


I'm not sure if that compiles or not, but is not an advisable pattern to follow. With the ability to do explicit interface implementation, you could theoretically provide two entirely different implementations for the IReadOnly and ICanReadAndWrite versiond of the Id property. Consider altering the ICanReadAndWrite interface by adding a setter method for the property rather than replacing the property.




回答5:


You can do it but I am not sure what you hope to accomplish by doing it.

public IReadOnly SomeMethod() {
   // return an instance of ICanReadAndWrite
}

This method will return a reference to an IReadOnly which means that it doesn't matter that you have returned an ICanReadAndWrite. Wouldn't this approach be better?

public interface IReadOnly
{
    String GetId();
}

public interface ICanReadAndWrite : IReadOnly
{
    String SetId();
}


来源:https://stackoverflow.com/questions/1399503/can-you-use-the-c-sharp-new-keyword-to-expand-properties-on-an-interface

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!