6

我了解“new”关键字如何隐藏派生类中的方法。但是,它对实现使用关键字的接口的类有什么影响?

考虑这个例子,我决定通过使其属性读/写来扩展接口。

public interface IReadOnly {

   string Id {
      get;
   }
}

public interface ICanReadAndWrite : IReadOnly  {

   new string Id {
      get;
      set;
   }
}

然后你可以做这样的事情:

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

这是糟糕的设计吗?它会导致我的实现 ICanReadAndWrite 的类出现问题吗?

编辑: 这是一个人为的例子,说明为什么我可能想做这样的事情:

假设我有一个返回 IShoppingCartItemReadWrite 的工厂类。然后我可以有一个服务层来操纵它的价格,改变东西等。然后,我可以将这些对象作为 IShoppingCartItemReadOnly 传递给某种不会改变它们的表示层。(是的,我知道它在技术上可以改变它们——这是一个设计问题,而不是安全性等)

4

5 回答 5

19

这不是一个特别糟糕的主意。您应该知道实现者可以(如果它隐式实现接口,则单个读/写属性可以满足两个接口)提供两种不同的实现:

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

顺便说一句,一般来说,new继承修饰符除了告诉编译器闭嘴并且不要抛出“你正在隐藏那个成员”警告之外什么都不做。省略它对编译的代码没有影响。

于 2009-09-09T12:58:16.307 回答
7

您不应该基于 IReadOnly 实现 ICanReadWrite,而是将它们分开。

IE。像这样:

public interface IReadOnly
{
    string Id
    {
        get;
    }
}

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

这是一个使用它们的类:

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

请注意,类中的相同属性可以支持这两个接口。

请注意,根据评论,获得强大解决方案的唯一方法是拥有一个包装器对象。

换句话说,这不好:

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

    public IReadOnly AsReadOnly()
    {
        return this;
    }
}

因为调用者可以这样做:

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

要获得强大的解决方案,您需要一个包装器对象,如下所示:

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; }
    }
}

在调用者使用反射之前,这将起作用并且是健壮的。

于 2009-09-09T13:00:36.153 回答
1

这是完全合法的,并且对于实现 ICanReadAndWrite 接口的类的含义仅仅是,当它被视为 IReadOnly 时,它只能读取,但当它被视为 ICanReadAndWrite 时,它​​将能够同时执行这两种操作。

于 2009-09-09T12:58:50.527 回答
0

我不确定这是否编译,但不是一个可取的模式。有了显式接口实现的能力,理论上你可以为属性的IReadOnlyICanReadAndWrite版本提供两种完全不同的实现IdICanReadAndWrite考虑通过为属性添加 setter 方法而不是替换属性来更改接口。

于 2009-09-09T12:55:54.947 回答
0

你可以做到,但我不确定你希望通过这样做来实现什么。

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

此方法将返回对 an 的引用,IReadOnly这意味着您是否返回了ICanReadAndWrite. 这种方法不是更好吗?

public interface IReadOnly
{
    String GetId();
}

public interface ICanReadAndWrite : IReadOnly
{
    String SetId();
}
于 2009-09-09T12:59:18.727 回答