考虑我有一个包含以下属性的接口
interface IFoo
{
Int32 Id { get; }
}
现在说我要创建一个IMutableFoo接口。从逻辑上讲,我认为以下是正确的:
interface IMutableFoo: IFoo
{
Int32 Id { set; }
}
我的想法是它会继承Id,然后在我的子界面中我会使它可以设置。令我惊讶的是,这不起作用。相反,我得到一个警告让我知道我实际上用IMutableFoo中的Id覆盖了IFoo中的Id。我试过改变{set; } 要得到;组;具有相同的结果。我该怎么做?在Java中,我只需添加一个setId方法。我如何在C#中执行此操作?谢谢!
答案 0 :(得分:4)
除了使用新的读/写属性定义新接口之外,没有什么可以做的。这是因为在谈论接口时没有继承的概念;相反,IMutableFoo
这样的接口是一个承诺,它的实现者也将实现接口IFoo
。但是,这两个接口都是独立定义的,并且保持独立。
MSDN documentation包含短语“接口可以继承其他接口”,但这是恕我直言,因为这里没有继承。 “派生”界面简单地描述了必须实现的一组更大的成员而不是“基础”界面。
IMutableFoo
等接口的实现者可以通过明确实现IFoo
并在IMutableFoo.Id
和IFoo.Id
的getter之间共享代码来提供您所定位的语义没有问题:
class Foo : IMutableFoo {
// IFoo is implemented explicitly
// "this" is of type Foo, and since IMutableFoo is implemented
// implicitly below, this.Id accesses the Id declared in IMutableFoo
Int32 IFoo.Id { get { return this.Id; } }
// IMutableFoo is implemented implicitly
// It could also be implemented explicitly, but the body of the
// IFoo.Id getter would need to change ("this" would no longer work)
public Int32 Id { get; set; }
}
不幸的是,没有强制实施者执行此操作的机制,但是一些好的文档可以在这里发挥很大作用 - 如果IFoo
和{{1}之间的关系更是如此很直观。
答案 1 :(得分:2)
在后代界面中重新声明Id确实隐藏了父级中的Id。
我为此使用了两种不同的解决方法,需要权衡我并不特别喜欢。
1 - 使用抽象甚至非抽象类而不是可变接口。
interface IFoo {
Int32 Id { get; }
}
abstract class MutableFoo: IFoo {
public abstract Int32 Id {get; set;}
}
最大的缺点是您的库的用户无法再编程到界面。
2 - 使用方法而不是属性。
interface IFoo {
Int32 Id { get; }
}
interface IMutableFoo: IFoo {
void SetId(Int32 value);
}
这并不理想,因为setter不是惯用的,并且看起来与getter断开连接。
答案 2 :(得分:1)
你可以做到
public interface IFoo
{
Int32 Id { get; }
}
public interface IFooMu : IFoo
{
new Int32 Id { get; set; }
}
class Foo : IFooMu
{
public Int32 Id { get; set; }
}
答案 3 :(得分:0)
将一个属性称为“不可变”与将其称为“只读”之间存在巨大差异。 “不可变”的对象属性是一种永远不会因任何原因而改变的对象属性,只要该对象存在即可。相比之下,“只读”属性是使用属性设置器无法更改的属性,但可能通过其他方式进行更改。
您的问题似乎是关于如何让对象以合理的方式支持只读和读写接口; Keith Nicholas的回答说明了正确的方法。请注意,如果使用显式接口实现,或者如果在vb.net而不是c#中编写类,则必须具有IFooMu.Id和IFoo.Id的单独实现;这是.net强加的烦人要求,但是c#允许一个公共属性作为只读,读写和只写属性的隐式定义。