将set访问器添加到类中的属性,该类派生自仅具有get访问器的抽象类

时间:2009-07-23 04:14:52

标签: c# interface properties abstract-class

我有一个抽象类 AbsClass ,它实现了一个接口 IClass IClass 有一些只有Get访问者的属性。 AbsClass IClass 的属性实现为要在 AbsClass 派生的类中定义的抽象属性。

因此,所有派生自 AbsClass 的类也需要通过与Get访问器具有相同的属性来满足 IClass 。但是,在某些情况下,我希望能够从 IClass 向属性添加set访问器。然而,如果我尝试使用set accessor覆盖 AbsClass 中的抽象属性,我会收到此错误

ConcClassA.Bottom.Set无法覆盖,因为AbsClass.Bottom没有可覆盖的集合访问者

请参阅下面的 ConcClassA

如果我有一个只实现 IClass 接口但没有继承自AbsClass的类,那么我可以添加一个没有问题的set访问器。请参阅下面的 ConcClassB

我可以在AbsClass的每个派生中实现IClass,而不是直接针对AbsClass。但是我从我的设计中知道每个AbsClass也需要一个IClass,所以我宁愿在层次结构中指定更高的值。

public interface IClass
{
    double Top
    {
        get;
    }
    double Bottom
    {
        get;
    }
}

abstract class AbsClass:IClass
{
    public abstract double Top
    {
        get;
    }

    public abstract double Bottom
    {
        get;
    }
}



class ConcClassA : AbsClass
{
    public override double Top
    {
        get { return 1; }
    }

    public override double Bottom
    {
        get { return 1; }

        //adding a Set accessor causes error:
        //ConcClassA.Bottom.Set cannot override because AbsClass.Bottom does not have an overridable set accessor

        //set { }
    }

}

class ConcClassB : IClass
{
    public double Top
    {
        get { return 1; }
        //added a set accessor to an interface does not cause problem
        set { }
    }
    public double Bottom
    {
        get { return 1; }
    }
}

更新

所以我认为如果我准确地解释我正在尝试做什么而不是使用抽象示例,这将更有意义。我在一家建筑公司工作,这些是与建筑设计项目相关的业务对象。

我有一个抽象类 RhNodeBuilding ,它代表项目中的一种类型的构建。有一些通用功能,例如具有楼层的功能,在 RhNodeBuilding 中定义。 RhNodeBuilding 还继承自另一个允许它成为更大项目树结构的抽象类。

RhNodeBuilding 从界面 IBuilding 实现,该界面定义了所有建筑应该能够提供的多个只读属性,例如 TopElevation BottomElevation 高度 NumberOfFloors 等等。请注意,还有其他建筑类型不是来自 RhNodeBuilding ,但仍需要实施 IBuilding

现在我有两种类型派生自 RhNodeBuilding MassBuilding FootPrintBuilding MassBuilding 由用户创建的3D形状定义。该形状具有 TopElevation BottomElevation ,应该可以通过相应的属性访问,但您不能通过更改属性来编辑3D卷。

另一方面,

FootPrintBuilding 由闭合曲线和高度范围定义,以挤出该曲线。因此,班级不仅应该能够返回当前的高程,而且还应该能够改变这些高度以重新定义高度范围。

总结一下。所有建筑物( IBuildings )都需要能够返回 TopElevation BottomElevation ,但并非所有建筑都应允许 TopElevation BottomElevation 可直接设置。所有 RhNodeBuildings 都是 IBuildings ,而来自 RhNodeBuilding 的类可能需要也可能不需要能够直接设置 TopElevation BottomElevation

public interface IBuilding
{
    double Top
    {
        get;
    }
    double Bottom
    {
        get;
    }
}

abstract class RhNodeBuilding:IBuilding
{
    public abstract double Top
    {
        get;
    }

    public abstract double Bottom
    {
        get;
    }
}



class MassBuilding: AbsClass
{

   //mass building only returns Top and Bottom properties so it works fine
    public override double Bottom
    {
        get { return 1; }
    }

    public override double Top
    {
        get { return 1; }
    }

}


class FootPrintBuilding: AbsClass
{
    //Top and Bottom of FootPrintBuilding can both be retrieved and set
    public override double Top
    {
        get { return 1; }
        //adding a Set accessor causes error:
        //cannot override because RhNodeBuilding.Top does not have an overridable set accessor

        //set { }
    }

    public override double Bottom
    {
        get { return 1; }

        //adding a Set accessor causes error:
        //cannot override because RhNodeBuilding.Bottom does not have an overridable set accessor

        //set { }
    }

}

现在似乎最好的选择是没有 RhNodeBuilding 实现 IBuilding ,而是让每个类都来自 RhNodeBuilding 实现IBuilding。这样我就可以直接从 IBuilding 定义属性,而不是覆盖。

abstract class AltRhNodeBuilding
{
    public abstract double Top
    {
        get;
    }
}


class AltFootPrintBuilding: IClass
{
    public override double Top
    {
        get { return 1; }

       //Can't add set access to overridden abstract property
        set { }
    }

    //No problem adding set accessor to interface property
    public double Bottom
    {
        get { return 1; }
        set {  }
    }
}

3 个答案:

答案 0 :(得分:10)

这就像它的工作方式一样,因为属性不是真正的虚拟 - 它们的存取方法是。因此,如果基类中没有set,则无法覆盖class AbsClassB : AbsClass { public override double Top { get { return ((ConcClassB)this).Top } } public override double Bottom { get { return ((ConcClassB)this).Bottom } } } class ConcClassB : AbsClassB { new public double Top { get { ... } set { ... } } new public double Bottom { get { ... } set { ... } } }

您可以做的是覆盖和shadow 基类实现,并提供您自己的新读/写属性。如果不在层次结构中引入额外的类,我不知道有什么方法可以做到这一点:

AbsClass

更好的想法是在Top.get中定义受保护的虚拟方法,并根据该方法实施Bottom.getConcClassB。然后,您可以直接在abstract class AbsClass : IClass { public double Top { get { return GetTop(); } } public double Bottom { get { return GetBottom(); } } protected abstract double GetTop(); protected abstract double GetBottom(); } class ConcClassB : AbsClass { new public double Top { get { ... } set { ... } } new public double Bottom { get { ... } set { ... } } protected override double GetTop() { return Top; } protected override double GetBottom() { return Bottom; } } 中覆盖该方法,并隐藏属性,而无需额外的类:

{{1}}

答案 1 :(得分:0)

我有点好奇为什么你希望这些实现类具有不属于公共接口的公共setter方法。听起来,你可能真的希望这些比公众更受限制吗?

除此之外,我很难想到这种方法存在问题。他们会“隐藏”超类中的任何属性,但是无论如何都没有超类中的属性设置器,所以这似乎没问题。看起来这可能是最简单的解决方法。

答案 2 :(得分:-13)

使用全局变量。