将 set 访问器添加到派生自仅具有 get 访问器的抽象类的类中的属性
我有一个抽象类,AbsClass,它实现了一个接口,IClass。 IClass 有几个仅具有 Get 访问器的属性。 AbsClass 将 IClass 的属性实现为要在派生自 AbsClass 的类中定义的抽象属性。
因此,所有从 AbsClass 派生的类也需要通过具有与 Get 访问器相同的属性来满足 IClass 的要求。 但是,在某些情况下,我希望能够将集合访问器添加到 IClass 的属性中。 然而,如果我尝试使用 set 访问器重写 AbsClass 中的抽象属性,则会收到此错误
ConcClassA.Bottom.Set 无法重写,因为 AbsClass.Bottom 没有可重写的 set 访问器
请参阅下面的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、Height、NumberOfFloors 等。请记住,还有其他建筑类型并非源自 RhNodeBuilding >,但仍需要实现IBuilding。
现在我有两种派生自 RhNodeBuilding 的类型:MassBuilding 和 FootPrintBuilding。 MassBuilding 由用户创建的 3D 形状定义。 该形状具有 TopElevation 和 BottomElevation,应该可以通过相应的属性进行访问,但您不应该能够通过更改属性来编辑 3D 体积。
另一方面,FootPrintBuilding 由闭合曲线和挤出该曲线的高度范围定义。 因此,该类不仅应该能够返回当前的海拔高度,而且还应该能够更改这些海拔高度以重新定义高度范围。
综上所述。 所有建筑物 (IBuildings) 都需要能够返回 TopElevation 和 BottomElevation,但并非所有建筑物都应允许 TopElevation > 或 BottomElevation 直接设置。 所有 RhNodeBuildings 都是 IBuildings,从 RhNodeBuilding 派生的类可能需要也可能不需要直接设置 TopElevation > 和底部标高。
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 { }
}
}
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 { }
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我有点好奇为什么您希望这些实现类具有不属于公共接口一部分的公共 setter 方法。 在我看来,您可能实际上希望这些内容比公开内容受到更多限制?
除此之外,我很难思考这种方法的问题。 他们会“隐藏”超类中的任何属性,但是超类中无论如何都没有属性设置器,所以这看起来没问题。 看起来这可能是最简单的解决方法。
I am kind of curious as to why you would want these implementation classes to have public setter methods that are not part of the public interface. It sounds to me like you may actually want these to be more restricted than public?
Other than that, I'm having a hard time thinking of a problem with this approach. They would "hide" any properties from the superclass, but there are no property setters in the superclass anyway, so that seems ok. It seems like it may be the simplest workaround.
使用全局变量。
Use a global variable.
它之所以如此工作,是因为属性并不是真正虚拟的——它们的访问器方法才是。 因此,如果基类中没有 set,则无法重写 set。
您可以做的是覆盖并隐藏基类实现,并提供您自己的新读/写属性。 我不知道有什么方法可以在不引入层次结构中的附加类的情况下实现此目的:
更好的想法是在
AbsClass
中定义受保护的虚拟方法,并实现Top.get
和Bottom.get
就该方法而言。 然后,您可以直接在ConcClassB
中重写该方法,并隐藏属性,而无需额外的类: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:
A better idea would be to define a protected virtual method right in
AbsClass
, and implementTop.get
andBottom.get
in terms of that method. Then you can override that method directly inConcClassB
, and shadow the properties, without the need for an extra class: