2009-09-09 48 views
6

我明白“新”关键字如何隐藏派生类中的方法。但是,它对实现使用关键字的接口的类有什么影响?您可以使用C#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传递给某种不会更改它们的表示层。 (是的,我知道它在技术上可以变化them--这是一个设计问题,而不是安全性等)

+0

您的具体示例没有多大意义。如果你可以读写,那么它不是只读的。 – 2009-09-09 13:16:17

+0

IShoppingCartItemReadWrite可以更改,但是如果我有一个IShoppingCartItemReadOnly的引用,除非将其转换为其他内容,否则它是只读的。 – user10789 2009-09-09 13:20:52

+0

请注意,您实际上并不需要“新”关键字。 – 2009-09-09 13:22:20

回答

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继承修饰符除了告诉编译器闭嘴,不要抛出“你隐藏该成员”的警告。省略它在编译的代码中不起作用。

+1

关于沉默编译器警告的好处!然而,它会抱怨,因为为类定义做类似的事情可以使它们以你可能不期望的方式行事。对于这种特殊情况,我想不出任何意外的行为......因此,这个问题。 – user10789 2009-09-09 13:11:11

+1

是的。当然,警告是有原因的。正如我在答案中所说的,唯一可能的问题是,您正在处理可能解析为不同实现的两个不同方法插槽。这是使用'new'的缺陷。对于'interfaces'来说,大多数情况下它并不是有害的,因为它们不提供任何实现,并且调用者期望无论如何都可以任意实现该方法。 – 2009-09-09 13:19:14

+1

新的关键字不是用于沉默编译器,而是清楚地指出“我不想重写任何成员,我的意图是隐藏它,并且我意识到这个事实”。警告是让你免于“无意中隐藏成员”。 – 2009-09-09 13:23:57

0

我不知道如果编译或没有,但不是一个明智的模式可循。由于能够执行明确的接口实现,因此理论上可以为Id属性的IReadOnlyICanReadAndWrite版本号提供两种完全不同的实现。考虑更改ICanReadAndWrite接口,方法是为该属性添加setter方法,而不是替换该属性。

+0

它绝对编译。如果您不添加新关键字,则会收到以下编译警告:'ICanReadAndWrite.Id'隐藏继承的成员'IReadOnly.Id'。如果需要隐藏,请使用新关键字。 – user10789 2009-09-09 13:00:06

+0

关于显式接口的实现,我假设如果你这样做,Id属性的两个完全不同的实现就是你想要的。 我对隐藏的疑难问题或可能由此方法导致的不太明显的问题更感兴趣。 – user10789 2009-09-09 13:02:09

+1

遗憾的是,仅仅向该属性添加setter将不起作用。如果设置者隐藏吸气剂,读取属性需要使用未遮蔽的吸气剂对类型进行类型转换。如果setter不影响getter,即独立的getter和setter都在范围内,那么在C#或vb.net中都不可用。 – supercat 2011-07-06 20:25:45

1

这是完全合法的,对你的类实现ICanReadAndWrite接口的影响可能仅仅是当它被当作IReadOnly处理时,它只能读取,但当被视为ICanReadAndWrite时,它将能够同时执行这两个操作。

0

你可以做到这一点,但我不知道你希望通过这样做来达到目的。

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

此方法会返回一个IReadOnly这意味着它并不重要,你已经返回ICanReadAndWrite的参考。这种方法不会更好吗?

public interface IReadOnly 
{ 
    String GetId(); 
} 

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

我想用一个简单的属性。 – user10789 2009-09-09 13:07:29

7

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

即。像这样:

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

这将工作,并坚定,直到调用者使用反射点。

+1

但是,您不能从ICanReadAndWrite投射到IReadOnly。当你有一个处理读/写对象的类时,这是非常有用的,然后只需要将一个只读对象返回给使用者。 – user10789 2009-09-09 13:05:01

+0

消费者可以回避。这不健壮。 – recursive 2009-09-09 13:12:22

+1

当然,它不是健壮的,但如果它能工作,它也不是最初的解决方案。摆脱可写性的唯一方法是返回明确阻止它的包装对象,即。只实现IReadOnly。 – 2009-09-09 13:15:19

相关问题