简体   繁体   English

为某些(但不是全部)继承的类引入setter

[英]Introduce setter for some - but not all - inherited classes

I am having a hard time implementing a property in C# that only has a getter in the abstract base class, but where I need to introduce a setter in one of the derived classes. 我很难在C#中实现一个只在抽象基类中有一个getter的属性,但是我需要在其中一个派生类中引入一个setter


Update: For a shorter explanation of a generalized example of this question, see this question . 更新:有关此问题的一般示例的简短说明, 请参阅此问题 The selected answer has explained why this is currently impossible to do in C#, however, in my mind no satisfactory solution has yet been provided. 选定的答案解释了为什么目前在C#中无法做到这一点,但是,在我看来还没有提供令人满意的解决方案。


An overview of my class diagram is shown below: 我的类图概述如下:

类图

My objective is that the two classes TextElementStatic and TextElementReferenceSource should have a Text property with both getters and setters, while the class TextElementReferenceTarget should have a Text property with only a getter. 我的目标是两个类TextElementStaticTextElementReferenceSource应该具有包含getter和setter的Text属性,而类TextElementReferenceTarget应该具有仅具有getter的Text属性。 I'm constantly using ITextElement while referencing all of these objects, and I need to ensure that the ITextElement interface only has a getter. 我在引用所有这些对象时经常使用ITextElement ,我需要确保ITextElement接口只有一个getter。 Also, the base class TextElement implements a lot of common code, so all classes need to inherit from that class. 此外,基类TextElement实现了许多通用代码,因此所有类都需要从该类继承。

My current code looks like this: 我当前的代码如下所示:

Interface: ITextElement 接口:ITextElement

public interface ITextElement
{
    string Text { get; }
}

Interface: ITextElementUpdatable 接口:ITextElementUpdatable

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

Abstract class: TextElement (This is where my problem is, explained below) 抽象类: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);
        }
    }
}

Abstract class: TextElementUpdatable 抽象类:TextElementUpdatable

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

Class: TextElementStatic 类:TextElementStatic

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

Class: TextElementReferenceSource 类: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; }
    }
}

Class: TextElementReferenceTarget 类:TextElementReferenceTarget

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

So, my issue is: I really want to declare the Text property in the base class TextElement abstract, because it should always be implemented in the derived classes (both TextElementUpdatable, TextElementReferenceSource and TextElementReferenceTarget implements this property). 所以,我的问题是:我真的想在基类TextElement抽象中声明Text属性,因为它应该总是在派生类中实现(TextElementUpdatable,TextElementReferenceSource和TextElementReferenceTarget都实现了这个属性)。 However, if I try to convert the property to public abstract string Text { get; } 但是,如果我尝试将属性转换为public abstract string Text { get; } public abstract string Text { get; } , then I receive an error in TextElementUpdatable specifying that public abstract string Text { get; } ,然后我收到错误在TextElementUpdatable指定

TextElementUpdatable.Text hides the inherited property TextElement.Text

Further, if I change the property in TextElementUpdatable from new to override the error message is replaced by: 此外,如果我将TextElementUpdatable中的属性从new更改为override则错误消息将替换为:

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

Now, I could go back to TextElement and change the property to public virtual string Text { get; private set; } 现在,我可以回到TextElement并将属性更改为public virtual string Text { get; private set; } public virtual string Text { get; private set; } public virtual string Text { get; private set; } and call it a day, since that method should never be called anyway (which is basically the solution I have now). public virtual string Text { get; private set; }和收工,因为该方法不应该被称为无论如何(这基本上是解决我现在有)。 However, if I or someone create another derived class later on, I want to force me/them to implement the Text-property, hence I would rather mark it abstract than provide a virtual implementation. 但是,如果我或某人稍后创建了另一个派生类,我想强迫我/他们实现Text-property,因此我宁愿将其标记为抽象而不是提供虚拟实现。

Any suggestions on how I can do this the right way - even if it should involve a lot of refactoring? 关于如何以正确的方式做到这一点的任何建议 - 即使它应该涉及大量的重构?

I know that I could separate the two objectives her, providing one inherited Text property with only a getter, and then introduce a SetText() method in the ITextElementUpdatable interface. 我知道我可以将她的两个目标分开,只提供一个继承的Text属性和一个getter,然后在ITextElementUpdatable接口中引入一个SetText()方法。 However, I'm wondering whether it is possible to find a good solution with properties only. 但是,我想知道是否有可能找到一个只有属性的好解决方案。


Another similar question, but without any answers I've been able to use: C# - What should I do when every inherited class needs getter from base class, but setter only for ONE inherited class 另一个类似的问题,但没有任何答案,我已经能够使用: C# - 当每个继承的类需要从基类获取getter时我该怎么办,但是setter只能用于一个继承的类

It is really an exciting desing problem, but.. You have to use the new keyword what is not a good practice. 这真是一个令人兴奋的设计问题,但是..你必须使用新的关键字,这不是一个好的做法。 Try to avoid them. 尽量避免它们。 Of course, property names can be the same in the interfaces, but if both implemented by a class (and one of the props defined without a setter), we have to implement them explicitelly. 当然,接口中的属性名称可以是相同的,但如果两者都是由类(以及没有setter定义的一个props)实现的,我们必须实现它们。 We have to accept that these properties "conflict". 我们必须接受这些属性“冲突”。 You could introduce abstract methods: 您可以介绍抽象方法:

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

It can be a bit confusing that you use the same property in your hierarchy with different meanings. 在层次结构中使用具有不同含义的相同属性可能会有点混乱。 Maybe the implementation of ITextElement.get_Text and ITextElementUpdatable.get_Text will diverge later - the interfaces define two independent behavior, and we do not use basic types all the time, like string. 也许ITextElement.get_Text和ITextElementUpdatable.get_Text的实现稍后会分歧 - 接口定义了两个独立的行为,我们不会一直使用基本类型,比如string。 So my suggestion is that you should have a property in ITextElement for read only purpose, and another property in ITextElementUpdatable with different name. 所以我的建议是你应该在ITextElement中有一个属性用于只读目的,而ITextElementUpdatable中的另一个属性具有不同的名称。 In this manner, your methods can be defined as abstract, of course. 通过这种方式,您的方法当然可以定义为抽象的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM