将 set 访问器添加到类中的属性,该类派生自仅具有 get 访问器的抽象类 [英] Adding a set accessor to a property in a class that derives from an abstract class with only a get accessor

查看:18
本文介绍了将 set 访问器添加到类中的属性,该类派生自仅具有 get 访问器的抽象类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个抽象类,AbsClass,它实现了一个接口,IClass.IClass 有几个只有 Get 访问器的属性.AbsClassIClass 的属性实现为抽象属性,这些属性将在从 AbsClass 派生的类中定义.

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

ConcClassA.Bottom.Set 无法覆盖,因为 AbsClass.Bottom 没有可覆盖的 set 访问器

参见下面的ConcClassA.

如果我有一个只实现了 IClass 接口的类,但不是从 AbsClass 继承的,那么我可以添加一个 set 访问器而不会出现问题.请参阅下面的 ConcClassB.

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

公共接口IClass{双顶{得到;}双底{得到;}}抽象类 AbsClass:IClass{公共抽象双顶{得到;}公共摘要双底{得到;}}类 ConcClassA : AbsClass{公共覆盖双顶{得到 { 返回 1;}}公共覆盖双底{得到 { 返回 1;}//添加一个 Set 访问器会导致错误://ConcClassA.Bottom.Set 不能覆盖,因为 AbsClass.Bottom 没有可覆盖的 set 访问器//放 { }}}类 ConcClassB : IClass{公共双顶{得到 { 返回 1;}//向接口添加set访问器不会导致问题放 { }}公共双底{得到 { 返回 1;}}}

<小时>

更新

所以我认为如果我准确地解释我想要做的事情而不是使用抽象的例子,这会更有意义.我在一家建筑公司工作,这些是与建筑设计项目相关的业务对象.

我有一个抽象类 RhNodeBuilding,它代表项目中的一种建筑类型.RhNodeBuilding 中定义了一些通用功能,例如设置楼层的能力.RhNodeBuilding 还从另一个抽象类继承,使其成为更大的项目树结构的一部分.

RhNodeBuilding 从接口 IBuilding 实现,该接口定义了所有建筑物都应该能够提供的许多只读属性,例如 TopElevationBottomElevationHeightNumberOfFloors 等等.请记住,还有其他建筑类型并非源自 RhNodeBuilding,但仍需要实施IBuilding.

现在我有两种源自 RhNodeBuilding 的类型:MassBuildingFootPrintBuilding.MassBuilding 由用户创建的 3D 形状定义.该形状有一个 TopElevation 和一个 BottomElevation,它们应该可以通过相应的属性访问,但您不能通过更改属性来编辑 3D 体积.>

FootPrintBuilding 另一方面由闭合曲线和高度范围定义,以通过该曲线挤出.因此,该类不仅应该能够返回当前的高度,而且还应该能够更改这些高度以重新定义高度范围.

总结一下.所有建筑物(IBuildings)都需要能够返回TopElevationBottomElevation,但并非所有建筑物都应允许TopElevation> 或 BottomElevation 直接设置.所有RhNodeBuildings都是IBuildings,从RhNodeBuilding派生的类可能需要也可能不需要能够直接设置TopElevation> 和 BottomElevation.

公共接口IBuilding{双顶{得到;}双底{得到;}}抽象类 RhNodeBuilding:IBuilding{公共抽象双顶{得到;}公共摘要双底{得到;}}类 MassBuilding:AbsClass{//mass building只返回Top和Bottom属性所以它工作正常公共覆盖双底{得到 { 返回 1;}}公共覆盖双顶{得到 { 返回 1;}}}类 FootPrintBuilding:AbsClass{//FootPrintBuilding的Top和Bottom都可以检索和设置公共覆盖双顶{得到 { 返回 1;}//添加一个 Set 访问器会导致错误://无法覆盖,因为 RhNodeBuilding.Top 没有可覆盖的 set 访问器//放 { }}公共覆盖双底{得到 { 返回 1;}//添加一个 Set 访问器会导致错误://无法覆盖,因为 RhNodeBuilding.Bottom 没有可覆盖的 set 访问器//放 { }}}

现在似乎最好的选择是不让 RhNodeBuilding 实现 IBuilding,而是让从 RhNodeBuilding 派生的每个类都实现建设.这样我就可以直接从 IBuilding 定义属性,而不是作为替代.

抽象类 AltRhNodeBuilding{公共抽象双顶{得到;}}类 AltFootPrintBuilding: IClass{公共覆盖双顶{得到 { 返回 1;}//不能添加对被覆盖的抽象属性的集合访问放 { }}//将set访问器添加到接口属性没问题公共双底{得到 { 返回 1;}放 {  }}}

解决方案

它的工作方式是这样的,因为属性并不是真正的虚拟 - 它们的访问器方法是.因此,如果基类中没有 set,您就不能覆盖它.

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

class AbsClassB : AbsClass{public override double Top { get { return ((ConcClassB)this).Top } }public override double Bottom { get { return ((ConcClassB)this).Bottom } }}类 ConcClassB : AbsClassB{新款公双顶{得到 { ... }放 { ... }}新款公双底{得到 { ... }放 { ... }}}

更好的想法是在 AbsClass 中定义一个受保护的虚拟方法,并在条款中实现 Top.getBottom.get那个方法的.然后您可以直接在 ConcClassB 中覆盖该方法,并隐藏属性,而无需额外的类:

抽象类 AbsClass : IClass{公共双顶{得到 { 返回 GetTop();}}公共双底{得到 { 返回 GetBottom();}}受保护的抽象双 GetTop();受保护的抽象双 GetBottom();}类 ConcClassB : AbsClass{新款公双顶{得到 { ... }放 { ... }}新款公双底{得到 { ... }放 { ... }}受保护的覆盖双 GetTop(){返回顶部;}受保护的覆盖双 GetBottom(){返回底部;}}

I have an abstract class, AbsClass that implements an interface, IClass. IClass has a couple properties with only Get accessors. AbsClass implements the properties of IClass as abstract properties to be defined in the classes that derive from AbsClass.

So all of the classes that derive from AbsClass will also need to satisfy IClass by having the same properties with Get accessors. However, in some cases I want to be able to add set accessors to the properties from IClass. Yet if I try to override the abstract properties in AbsClass with a set accessor I get this error

ConcClassA.Bottom.Set cannot override because AbsClass.Bottom does not have an overridable set accessor

See ConcClassA below.

If I have a class that is only implementing the IClass interface, but not inheriting from AbsClass then I am able to add a set accessor with out problems. See ConcClassB below.

I could just implement IClass at each derivation of AbsClass rather then directly for AbsClass. Yet I know from my design that every AbsClass needs to also be an IClass so I'd rather specify that higher up in the hierarchy.

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


Update

So I think this will make more sense if I explain exactly what I'm trying to do rather then using the abstract example. I work for an Architecture firm and these are business objects related to an architectural design project.

I have an abstract class RhNodeBuilding that represents one type of building on a project. There is some general functionality, like the ability to have floors, that is defined in RhNodeBuilding. RhNodeBuilding also inherits from another abstract classes that allow it be part of a larger project tree structure.

RhNodeBuilding implements from an interface IBuilding which defines a number of read only properties that all buildings should be able to provide such as TopElevation, BottomElevation, Height, NumberOfFloors, etc..etc.. Keep in mind there are other building types that do not derive from RhNodeBuilding, but still need to implement IBuilding.

Right now I have two types that derive from RhNodeBuilding: MassBuilding and FootPrintBuilding. MassBuilding is defined by a 3D shape created by the user. That shape has a TopElevation and a BottomElevation that should be accessible through the corresponding properties, but you shouldn't be able to edit the 3D volume by changing the properties.

FootPrintBuilding on the other hand is defined by a closed curve and a height range to extrude that curve through. So not only should the class be able to return what the current elevations are but these elevations should also be able to be changed to redefine the height range.

So in summary. All buildings (IBuildings) need to be able to return a TopElevation and BottomElevation, but not all buildings should allow TopElevation or BottomElevation to be set directly. All RhNodeBuildings are IBuildings, and classes that derive from RhNodeBuilding may or may not need to be able to directly set TopElevation and 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 { }
    }

}

Right now it seems like the best option is to not have RhNodeBuilding implement IBuilding, but rather have every class that derives from RhNodeBuilding implement IBuilding. That way I can define the properties from IBuilding directly rather then as overrides.

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 {  }
    }
}

解决方案

This works the way it does because properties aren't truly virtual - their accessor methods are. Thus, you cannot override set if there wasn't one in the base class.

What you can do is override and shadow the base class implementation, and provide your own new read/write properties. I don't know of any way to do this without introducing an additional class in the hierarchy:

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 { ... }
    }
}

A better idea would be to define a protected virtual method right in AbsClass, and implement Top.get and Bottom.get in terms of that method. Then you can override that method directly in ConcClassB, and shadow the properties, without the need for an extra class:

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

这篇关于将 set 访问器添加到类中的属性,该类派生自仅具有 get 访问器的抽象类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆