2011-05-19 65 views
16

为什么在实现接口时允许更改属性中getter或setter的可见性和存在性?将替代者添加到替代属性

interface IFoo 
{ 
    string Bar { get; } 
} 

class RealFoo : IFoo 
{ 
    public RealFoo(string bar) 
    { 
     this.Bar = bar; 
    } 

    public string Bar { get; private set; } 
} 

class StubFoo : IFoo 
{ 
    public string Bar { get; set; } 
} 

...并且在执行抽象类时做法不合法吗?

abstract class AbstractFoo : IFoo 
{ 
    public abstract string Bar { get; } 
} 

class RealFoo : AbstractFoo 
{ 
    public RealFoo(string bar) 
    { 
     this.Bar = bar; 
    } 

    // Cannot override because 'Bar' does not have an overridable set accessor 
    public override string Bar { get; private set; } 
} 
+2

在您的示例中,您将*代码添加到接口实现中,因为没有setter,但您正在改变抽象类实现中的可见性。所以它不一样。 – jv42 2011-05-19 12:11:55

+1

@ jv42因为setter是* private *,所以在实现中没有改变可视性。限制是任意的和愚蠢的...... C#也可以被指定为允许覆盖仅适用于当它们不是私有时获取或设置。或者它可以允许'公共字符串Bar {override get;私人设置; }' – 2014-10-25 00:35:00

+0

@JimBalter我同意可能有机制来改变访问者的可见性。您可能想要检查C#6中会发生什么,我已经看到了一些有趣的新属性。 – jv42 2014-10-26 09:42:00

回答

12

该接口声明该类必须具有的公共属性(它只是一个契约)。这意味着你需要拥有这些属性,但可以添加到它们。

抽象类声明这些属性的实际结构。所以如果你在抽象基础中没有setter,你就不能在实现中添加它。
当您编写override override修饰符时,它会在基类中查找要覆盖的内容。

0

抽象类是一个无法实例化的类,但必须从中继承。抽象类可以完全实现,但通常部分实现或根本不实现,从而封装了继承类的通用功能。

相反,接口是一个完全抽象的成员集合,可以被认为是定义行为契约。接口的实现完全由开发人员完成。

从MSDN http://msdn.microsoft.com/en-us/library/scsyfw1d(v=VS.71).aspx

+1

好吧,这意味着在类层次结构中添加抽象基类将强制您在某些派生类中添加空/异常抛出的setter实现。不是最优雅的行为。 – ndeuma 2011-05-19 12:27:22

+2

这个“答案”并没有涉及实际提出的问题。 – 2014-10-25 00:39:39

0

两者按照C#规范

是,用于实现 的接口可以不具有 存取改性剂的存取器。如果只有一个 访问被用于实现 接口,其他访问可以用访问修饰符来声明 :

public interface I 
{ 
    string Prop { get; } 
} 
public class C: I 
{ 
    public Prop { 
    get { return "April"; }  // Must not have a modifier here 
     internal set {...} // Ok, because I.Prop has no set accessor 
    } 
} 

这意味着它是确定已修改了一个类实现的访问接口。然而,抽象类声明了一个实现,你不能用派生类来改变它。

+1

'abstract'属性没有实现。 “抽象类声明实现”是什么意思?抽象类是否任意限制了实现,而接口不会随意限制实现? – binki 2014-01-29 17:48:56

+0

是的,抽象类可以有实现。抽象类可能缺乏实现或可能不完全实现。抽象类只能用于派生其他类。 – 2014-01-30 11:56:56

+1

“抽象类可以有实现” - @ binki表示抽象*属性*没有实现。你的回应没有解决他的评论。没有什么理由让C#不允许像'public string Bar {override get;私人设置; }' – 2014-10-25 00:38:49

7

如果你将吸气剂和吸气剂想象成它们最终成为的方法,它可能会变得更加清晰。

在接口的情况下,你要定义这样的:“实现这个接口必须包括该方法的所有班”

interface IFoo 
{ 
    string GetBar(); 
} 

这可以理解为 的你都做类:

class RealFoo : IFoo 
{ 
    public string GetBar(); 
    private void SetBar(string value); 
} 

它们也实现了SetBar(),但是这并不重要;他们履行了界面定义的合同并且是有效的。

抽象类,而另一方面是这样的:

abstract class AbstractFoo : IFoo 
{ 
    public abstract string GetBar(); 
} 

这意味着所有子类必须GetBar()

您所做的类提供了一个方法体是这样的:

class RealFoo : AbstractFoo 
{ 
    public override string GetBar(); 
    public override void SetBar(string value); 
} 

通过将override修饰符放在SetBar方法的前面,编译器期望在基类中找到抽象或虚拟版本。你没有,所以编译失败。

+0

这意味着属性实际上只是setters和getters的捷径,并且对于良好的oo-design原则没有任何规定。 – 2013-03-16 23:03:05

+2

所以你间接地说C#将不得不添加像'public string Bar {override get;组; }'然后我们在实现抽象属性的时候就不会受到任意限制。这实际上是有道理的。 – binki 2014-01-29 17:53:46

+1

@binki它确实有道理,这就是为什么这些答案没有,限制是任意的,而且设计很差。 C#不需要“添加语法”,它可以简单地采用OP提供的语法并对其进行智能处理,而不是要求我们明确提供后备变量。 – 2014-10-25 00:29:38