【问题标题】:Introduce setter for some - but not all - inherited classes为某些(但不是全部)继承的类引入 setter
【发布时间】:2014-07-13 01:32:15
【问题描述】:

我很难在 C# 中实现一个在抽象基类中只有一个 getter 的属性,但是我需要在其中一个中引入一个 setter派生类。


更新:有关此问题的一般示例的简短说明,see this question。所选答案解释了为什么目前在 C# 中无法做到这一点,但是,在我看来,还没有提供令人满意的解决方案。


我的类图概览如下所示:

我的目标是 TextElementStaticTextElementReferenceSource 这两个类应该有一个 Text 属性,其中包含 getter 和 setter,而类 TextElementReferenceTarget 应该有一个只有 getter 的 Text 属性。我在引用所有这些对象时经常使用 ITextElement,并且我需要确保 ITextElement 接口只有一个 getter。另外,基类TextElement实现了很多通用代码,所以所有的类都需要继承自该类。

我当前的代码如下所示:

接口:ITextElement

public interface ITextElement
{
    string Text { get; }
}

接口:ITextElementUpdatable

public interface ITextElementUpdatable : ITextElement
{
    new string Text { get; set; }
}

抽象类:TextElement (这是我的问题所在,如下所述)

public abstract class TextElement : ITextElement
{
    // I want to mark this 'abstract', but that causes my problem
    public virtual string Text
    {
        get
        {
            // NOTE: This should never be called
            Debug.Fail("Called virtual Text getter that should never be called");
            return default(string);
        }
    }
}

抽象类:TextElementUpdatable

public abstract class TextElementUpdatable : TextElement, ITextElementUpdatable
{
    // Should have both a getter and a setter  
    public new virtual string Text { get; set; }
}

类:TextElementStatic

public class TextElementStatic : TextElementUpdatable
{
    // Should have both a getter and a setter
    // No Text property declaration
    // Inherits Text property from TextElementUpdatable
}

类:TextElementReferenceSource

public class TextElementReferenceSource : TextElementUpdatable
{      
    // Should have both a getter and a setter     
    public override string Text
    {
        get { return _internalobject.Text; }
        set { _internalobject.Text = value; }
    }
}

类:TextElementReferenceTarget

public class TextElementReferenceTarget : TextElement
{
    // Should ONLY have a getter
    public override string Text
    {
        get { return _internalobject.Text; }
    }
}

所以,我的问题是:我真的想在基类 TextElement 抽象中声明 Text 属性,因为它应该始终在派生类中实现(TextElementUpdatable、TextElementReferenceSource 和 TextElementReferenceTarget 都实现了这个属性)。但是,如果我尝试将属性转换为 public abstract string Text { get; },那么我会在 TextElementUpdatable 中收到一个错误,指定

TextElementUpdatable.Text hides the inherited property TextElement.Text

此外,如果我将 TextElementUpdatable 中的属性从 new 更改为 override,则错误消息将替换为:

Cannot override because TextElement.Text does not have an overridable set accessor

现在,我可以回到 TextElement 并将属性更改为 public virtual string Text { get; private set; } 并每天调用它,因为无论如何都不应该调用该方法(这基本上是我现在的解决方案) .但是,如果我或某人稍后创建另一个派生类,我想强制我/他们实现 Text-property,因此我宁愿将其标记为抽象而不是提供虚拟实现。

关于如何以正确的方式做到这一点的任何建议 - 即使它应该涉及大量重构?

我知道我可以把她的两个目标分开,提供一个继承的Text属性,只有一个getter,然后在ITextElementUpdatable接口中引入SetText()方法.但是,我想知道是否可以仅使用属性找到一个好的解决方案。


另一个类似的问题,但我无法使用任何答案:C# - What should I do when every inherited class needs getter from base class, but setter only for ONE inherited class

【问题讨论】:

  • +1 表示非常解释得很好且书面的问题。不幸的是,我认为我没有给你一个好的答案,在我看来你已经找到了最好的/唯一的解决方法。祝你好运!
  • this 有帮助吗?
  • @WilliamBarbosa 谢谢,我在研究期间没有找到那个。它看起来像同样的问题。不过,我对答案并不特别满意,因为这对我来说似乎太过分了。然后我宁愿使用SetProperty() 解决方案,因为我发现它更清洁 - 除非有人可以提供不同的答案..

标签: c# .net inheritance properties overriding


【解决方案1】:

这确实是一个令人兴奋的设计问题,但是.. 您必须使用 new 关键字这不是一个好习惯。尽量避免它们。 当然,接口中的属性名称可以相同,但如果两者都由一个类实现(并且其中一个没有 setter 定义的属性),我们必须显式地实现它们。我们不得不接受这些属性“冲突”。 你可以引入抽象方法:

public abstract class TextElement : ITextElement
{
    public string Text { get { return GetText(); } }

    protected abstract string GetText();
}

public abstract class TextElementUpdatable : TextElement, ITextElementUpdatable
{
    string ITextElementUpdatable.Text
    {
        get { return GetText(); }
        set { SetText(value); }
    }

    protected abstract void SetText(string text);
}

【讨论】:

  • +1 是一个不错的答案,但是,在我看来,仅使用属性 并不能满足问题的意图。如果我正在实现受保护的 SetText() 方法并且必须引入冲突属性,我认为从设计的角度来看,只提供一个公共的 SetText() 并将该属性仅保留为 getter,正如问题中所讨论的那样。可以在此答案中找到与您类似的方法:stackoverflow.com/a/1489383/521773
【解决方案2】:

在层次结构中使用具有不同含义的相同属性可能会有点令人困惑。也许 ITextElement.get_Text 和 ITextElementUpdatable.get_Text 的实现会在后面出现分歧——接口定义了两个独立的行为,我们并不一直使用基本类型,比如字符串。 所以我的建议是,您应该在 ITextElement 中拥有一个用于只读目的的属性,并在 ITextElementUpdatable 中拥有另一个名称不同的属性。通过这种方式,您的方法当然可以定义为抽象的。

【讨论】:

  • 嗯,这并不是真的对不同的属性有不同的含义。它是一个属性,在某些派生类中是只读的,在某些派生类中是读写的。我不确定我是否同意你在这种特定情况下的困惑。
猜你喜欢
  • 2021-12-26
  • 1970-01-01
  • 2019-05-07
  • 1970-01-01
  • 2012-01-25
  • 1970-01-01
  • 1970-01-01
  • 2018-05-06
  • 1970-01-01
相关资源
最近更新 更多