【问题标题】:Override abstract readonly property to read/write property将抽象只读属性覆盖为读/写属性
【发布时间】:2010-12-02 03:22:29
【问题描述】:

我只想强制在基本抽象类的给定属性上实现 C# getter。如果需要,派生类还可以为该属性提供一个设置器,以供公众使用静态绑定类型。

给定以下抽象类:

public abstract class Base
{
    public abstract int Property { get; }
}

如果我想要一个也实现 setter 的派生类,我可以天真地尝试:

public class Derived : Base
{
    public override int Property
    {
        get { return field; }
        set { field = value; } // Error : Nothing to override.
    } 

    private int field;
}

但后来我得到一个语法错误,因为我试图覆盖不存在的 setter。我尝试了其他一些方法,例如将 base setter 声明为私有等,但我仍然偶然发现各种错误阻止我这样做。必须有办法做到这一点,因为它不会破坏任何基类契约。

顺便说一句,它可以用接口来完成,但我真的需要那个默认实现。

我经常遇到这种情况,我想知道是否有隐藏的 C# 语法技巧可以做到这一点,否则我将忍受它并实现手动 SetProperty() 方法。

【问题讨论】:

标签: c# properties abstract


【解决方案1】:

您可以使用以下构造函数来执行此操作;

public abstract class Base
{
    public abstract int Property { get; }
}


public class Derived : Base
{
    public Derived(string Property) : base(Property)
    {

    }
}

【讨论】:

    【解决方案2】:

    我有一个类似的需求,我需要一个能够在两个松散相关的类之间共享通用排序功能的接口。其中一个有一个只读的 Order 属性,另一个有一个读写的 Order 属性,但我需要一种从两个类中以相同方式读取该属性的方法。

    事实证明,这可以通过将只读值隐藏在派生接口中来完成。这是我的做法。

    interface ISortable
    {
        int Order { get; }
    }
    
    interface ISortableClass2
        : ISortable
    {
        // This hides the read-only member of ISortable but still satisfies the contract
        new int Order { get; set; }
    }
    
    class SortableClass1
        : ISortable
    {
        private readonly int order;
    
        public SortableClass1(int order)
        {
            this.order = order;
        }
    
        #region ISortable Members
    
        public int Order
        {
            get { return this.order; }
        }
    
        #endregion
    }
    
    class SortableClass2
        : ISortableClass2
    {
        #region ISortableClass2 Members
    
            public int Order { get; set; } 
    
        #endregion
    }
    
    class RunSorting
    {
        public static void Run()
        {
            // Test SortableClass1
            var list1 = new List<SortableClass1>();
    
            list1.Add(new SortableClass1(6));
            list1.Add(new SortableClass1(1));
            list1.Add(new SortableClass1(5));
            list1.Add(new SortableClass1(2));
            list1.Add(new SortableClass1(4));
            list1.Add(new SortableClass1(3));
    
            var sorted1 = SortObjects(list1);
    
            foreach (var item in sorted1)
            {
                Console.WriteLine("SortableClass1 order " + item.Order);
            }
    
            // Test SortableClass2
            var list2 = new List<SortableClass2>();
    
            list2.Add(new SortableClass2() { Order = 6 });
            list2.Add(new SortableClass2() { Order = 2 });
            list2.Add(new SortableClass2() { Order = 5 });
            list2.Add(new SortableClass2() { Order = 1 });
            list2.Add(new SortableClass2() { Order = 4 });
            list2.Add(new SortableClass2() { Order = 3 });
    
            var sorted2 = SortObjects(list2);
    
            foreach (var item in sorted2)
            {
                Console.WriteLine("SortableClass2 order " + item.Order);
            }
        }
    
        private static IEnumerable<T> SortObjects<T>(IList<T> objectsToSort) where T : ISortable
        {
            if (objectsToSort.Any(x => x.Order != 0))
            {
                return objectsToSort.OrderBy(x => x.Order);
            }
    
            return objectsToSort;
        }
    }
    

    【讨论】:

      【解决方案3】:

      这会满足你的需要吗?

      public abstract class TheBase
      {
          public int Value
          {
              get;
              protected set;
          }
      }
      public class TheDerived : TheBase
      {
          public new int Value
          {
              get { return base.Value; }
              set { base.Value = value; }
          }
      }
      

      virtual 已删除,但基值仍然是该值的唯一存储空间。所以这应该显示“5”。并且编译器应该对b.Value = 4; 大惊小怪

      TheDerived d = new TheDerived();
      d.Value = 5;
      TheBase b = d;
      //b.Value = 4;    // uncomment for compiler error
      cout << "b.Value == " << b.Value << endl;
      

      -杰西

      【讨论】:

        【解决方案4】:

        类似的东西呢:

        public abstract class Base
        {
            public virtual int Property
            {
                get { return this.GetProperty(); }
                set { }
            }
        
            protected abstract int GetProperty();
        }
        

        【讨论】:

        • 现在任何继承者都必须覆盖它们——有点多余?
        • 仅在覆盖属性时。否则,没有虚拟属性实际上可能是可接受的替代方案。
        • 如果不覆盖该属性,设置的目的是非常...不寻常的。
        • 你是对的,我完全误读了答案。它必须在某个地方更新。
        • @Marc 据我所知它满足了要求,唯一需要注意的是,添加 setter 还需要一个 getter,它只调用 base。
        【解决方案5】:

        你不能直接这样做,因为你不能newoverride在同一类型上具有相同的签名;有两个选项 - 如果你控制基类,添加一个 second 属性:

        public abstract class Base
        {
            public int Property { get { return PropertyImpl; } }
            protected abstract int PropertyImpl {get;}
        }
        public class Derived : Base
        {
            public new int Property {get;set;}
            protected override int PropertyImpl
            {
                get { return Property; }
            }
        }
        

        否则,您可以在类层次结构中引入额外的级别:

        public abstract class Base
        {
            public abstract int Property { get; }
        }
        public abstract class SecondBase : Base
        {
            public sealed override int Property
            {
                get { return PropertyImpl; }
            }
            protected abstract int PropertyImpl { get; }
        }
        public class Derived : SecondBase
        {
            public new int Property { get; set; }
        
            protected override int PropertyImpl
            {
                get { return Property; }
            }
        }
        

        【讨论】:

        • 你的解决方案很有趣,我会稍微思考一下。
        • 您的解决方案是最接近事物的方法。但我认为不强制派生类做杂技是不可能的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-21
        • 2011-06-08
        • 1970-01-01
        • 2011-08-22
        • 2018-10-17
        • 1970-01-01
        相关资源
        最近更新 更多