【问题标题】:Override get, but not set覆盖获取,但未设置
【发布时间】:2011-01-02 20:23:12
【问题描述】:

我有一个定义了get 的抽象类,但没有定义set,因为就该抽象类而言,它只需要一个get

public abstract BaseClass
{
  public abstract double MyPop
  {get;}
}

但是,在某些派生类中,我需要一个set 属性,所以我正在研究这个实现

public class DClass: BaseClass
{
  public override double MyPop
  {get;set;}
}

问题是,我得到一个编译错误,说

*.set: 不能覆盖,因为 *.没有可覆盖的 set 访问器。

尽管我认为上述语法是完全合法的。

对此有任何想法吗?解决方法,或者为什么会这样?

编辑:我能想到的唯一方法是将getset 都放在抽象类中,如果调用set,则让子类抛出NotImplementedException这不是必需的。这是我不喜欢的东西,还有special setter method

【问题讨论】:

  • 让我们稍微分解一下。您需要构建一组类,这些类公开一个读取double 值的方法,该值将在每个类中专门实现。有时需要设置此值,因此其中一些类应公开设置此值的方法。这是正确的吗?您需要使用多少级继承?
  • @Codesleuth:是的。至于有多少级继承,我不知道这与问题有什么关系?
  • @David,具有讽刺意味的是,这似乎是一个我不想接受答案的问题。
  • 我不明白为什么接口可以做到这一点,但抽象类却不行。什么给了?
  • 这太糟糕了。有谁明白为什么这是不可能的? get 和 set 属性在编译过程中确实被转换为方法等价物,不是吗?那么这些方法的虚拟性可以是孤立的事情吗?编辑:我想也许我在这里找到了答案:stackoverflow.com/questions/82437/…

标签: c#


【解决方案1】:

即使这个帖子很旧,我也会提出我的解决方案,以防它对某人有所帮助。它不是我自己的,而是基于其他 SO 主题的答案。

public abstract BaseClass
{
  public double MyPoP { get { return GetMyPoP; } }

  protected abstract double GetMyPoP { get; }
}

public class DClass: BaseClass
{
  public new double MyPoP { get; set; }

  protected override double GetMyPop { get { return MyPoP; } }
}

此解决方案为需要修改访问器的每个此类属性添加了额外的代码行。但是,外部可见性没有变化,并提供了所需的功能。

【讨论】:

    【解决方案2】:

    C# 6.0 中的新功能:

    如果您只在构造函数中调用 setter,则可以使用只读属性解决此问题。

    void Main()
    {
        BaseClass demo = new DClass(3.6);
    }
    
    public abstract class BaseClass
    {
        public abstract double MyPop{ get; }
    }
    
    public class DClass : BaseClass
    {
        public override double MyPop { get; }
        public DClass(double myPop) { MyPop = myPop;}
    }
    

    【讨论】:

    • 虽然这是事实,但它也不是解决问题的通用解决方案。当然,在很多情况下都需要公共设置器。
    【解决方案3】:

    这是不可能的原因是由于参数被 C#“魔术”到存在的方式。当您定义一个参数时,C# 会创建一个 private 字段,由隐式 getter 和 setter 操作。如果基类中没有设置器,则不可能从编写在子类中的方法更改此变量(因为私有标志甚至禁止子类访问它)。通常发生的是它使用基类的隐式设置器。

    如果不是所有子类都能做到,我不建议将集合放在基类中,因为这违背了多态编程的整个原则(抽象类中定义的任何抽象方法都必须由子类实现) .如其他答案中所述,创建一个特殊的 setter 方法可能是最好的方法。

    【讨论】:

      【解决方案4】:

      围攻

      abstract class TestBase
      {
          public abstract int Int { get; }
      }
      
      class TestDerivedHelper : TestBase
      {
          private int _Int;
          public override int Int
          {
              get
              {
                  return _Int;
              }
          }
      
          protected void SetInt(int value)
          {
              this._Int = value;
          }
      }
      
      class TestDerived : TestDerivedHelper
      {
          public new int Int
          {
              get { return base.Int; }
              set { base.SetInt(value); }
          }
      }
      

      使用 TestDerived 将具有您正在寻找的功能。这 我可以从这种方法中看到的唯一缺点是您必须实现 TestDerivedHelper 中的每个抽象方法,但它为您提供了更多 稍后控制。

      我使用这种方法并且非常适合我。 另外,我也将我的“TestDerivedHelper”类抽象化了,那么所有的方法都必须在“TestDerived”类上实现。

      【讨论】:

        【解决方案5】:

        如果BaseClass 在您自己的代码库中,那么您可以这样做:

        abstract public class BaseClass
        {
            abstract public double MyPop { get; protected set; }
        }
        
        public class DClass : BaseClass
        {
            private double _myProp;
            public override double MyProp
            {
                get { return _myProp; }
                protected set { _myProp = value; }
            }
        }
        

        编辑:然后您可以在 DClass SetMyProp(double myProp) 等中创建一个公共方法。域模型的类设计应该清楚地说明为什么不能直接在基类中设置属性以及为什么可以在派生类中这样做。

        【讨论】:

        • 好的,但是那些不需要设置MyPop的子类呢?
        • 也许他们只能从 BaseClass 派生而不是从 DClass 派生?
        • 我认为这对我的应用程序来说不是一个好主意;应该为is a 关系保留继承,而不是解决语言限制;除了我在这里的应用程序中将继承用于其他更现实的目的。
        • 我实际上从来没有遇到过这个问题,而且我对 OO 的正确性很狂热,相信我 ;-) ...(尽管 OO 有限制,请注意)...也许当你告诉关于你的具体情况,我可以就你的模型提出建议。
        • 我在想一个真实世界的例子,我想看看你想要建模什么。例如,您的 Animal、Giraffe 和 Lion 类或 CelestialBody、Meteor 和 Planet 类。
        【解决方案6】:

        编辑:

        好的,我可能对这个回复很仓促,但我现在已经考虑了更多。

        你必须使用抽象基类吗?如果不需要,试试这个:

        public interface ISomeRelevantName
        {
            double MyPop { get; }
        }
        
        public class DClass : ISomeRelevantName
        {
            public double MyPop { get; set; }
        }
        

        【讨论】:

        • 会抱怨来自BaseClass 的抽象属性MyPop 没有在派生类中实现。
        • 嗯,我的回答让我感到羞耻:(我正在尝试通过编辑来纠正这个问题。
        【解决方案7】:

        你可以这样做:

        abstract class TestBase { public abstract int Int { get; } }

        class TestDerivedHelper : TestBase
        {
            private int _Int;
            public override int Int
            {
                get
                {
                    return _Int;
                }
            }
        
            protected void SetInt(int value)
            {
                this._Int = value;
            }
        }
        
        class TestDerived : TestDerivedHelper
        {
            public new int Int
            {
                get { return base.Int; }
                set { base.SetInt(value); }
            }
        }
        

        使用 TestDerived 将拥有您正在寻找的功能。我可以从这个方法中看到的唯一缺点是您必须在 TestDerivedHelper 中实现每个抽象方法,但它会在以后为您提供更多控制权。

        希望这会有所帮助。 ;)

        【讨论】:

          【解决方案8】:

          如果你找到了一种方法,你确定做你想做的事情会是一个好的设计吗?

          它将允许子类的对象进行父类的对象无法进行的状态更改。这不会违反里氏替换原则吗?

          【讨论】:

            【解决方案9】:
            public abstract class BaseClass
            {
                public abstract double MyPop { get; }
            }
            
            public class DClass: BaseClass
            {
                private double _myPop = 0;
                public override double MyPop 
                {
                    get { return _myPop; }
                }
            
                // some other methods here that use the _myPop field
            }
            

            如果您需要从DClass 外部设置属性,那么将setter 放入基类可能会更好。

            【讨论】:

              【解决方案10】:

              不可能做你想做的事。您必须在抽象属性中定义 setter,否则您将无法正确覆盖它。

              我知道在哪里定义 getter 和实现 getter/setter 的唯一情况是使用接口:

              public interface IBaseInterface
              {
                  double MyPop { get; }
              }
              
              public class DClass : IBaseInterface
              {
                  public double MyPop { get; set; }
              }
              

              【讨论】:

              • 不错的方法;但有时你只需要使用抽象类,而不是接口。
              • C# 8 部分缓解了 Graviton 的担忧,其中引入了Default Interface Methods
              【解决方案11】:

              一个可能的答案是覆盖 getter,然后实现一个单独的 setter 方法。如果您不希望在基础中定义属性设置器,那么您没有很多其他选择。

              public override double MyPop
              {
                  get { return _myPop; }
              }
              
              public void SetMyPop(double value)
              {
                  _myPop = value;
              }
              

              【讨论】:

                【解决方案12】:

                您不能覆盖 set 访问器,因为基类没有定义 set 访问器。

                您可以做的是使用new 关键字来隐藏基类实现,但这可能不是您想要的。

                【讨论】:

                • 基类是抽象的,没有实现,因此new不能工作。
                • 澄清:这不起作用,因为派生类没有实现抽象属性。以上评论可能有点不准确。
                • 我的评论也具有误导性(建议“新”完全可以工作)所以我删除了它。不过感谢您的更新。
                【解决方案13】:

                为什么不在基类中拥有一个具有私有 setter 的属性,然后在需要该 setter 的子类中覆盖它并将其公开。

                【讨论】:

                • 抽象访问器不能是私有的
                • 一个abstract属性的getset访问者的private模拟是protected。所以在你想要的基类中:public abstract MyProp { get; protected set; }
                猜你喜欢
                • 2012-09-11
                • 2014-03-11
                • 1970-01-01
                • 1970-01-01
                • 2011-11-30
                • 1970-01-01
                • 1970-01-01
                • 2011-09-24
                • 2016-07-29
                相关资源
                最近更新 更多