C# 访问子类属性

4
我有几个类,我在尝试从其他类方法中访问子类定义的属性时遇到了问题。
我有一个名为“Section”的基类和一些子类,例如“SectionPlane : Section”。每个子类都定义了不同的字段和属性(在“SectionPlane”中,可以找到私有字段“_t”和公共属性“t”,而在“SectionExtruded : Section”中,我有私有字段“A”和公共属性“A”)。 类Section:
// General section object
public abstract class Section
{
    public Section()
    {}
}

平面截面类

// Section object representing a plane with thickness t
public class SectionPlane : Section
{
    private double _t;

    public SectionPlane(double t)
    {
        this.t = t;
    }

    public double t
    {
        get
        {
            return _t;
        }
        set
        {
            _t = value;
        }
    }
}

挤出剖面类

// Section object of some geometry with cross section area A extruded along the element it is assigned to.
public class SectionExtruded : Section
{
    private double _A;

    public SectionExtruded(double A)
    {
        this.A = A;
    }

    public double A
    {
        get
        {
            return _A;
        }
        set
        {
            _A = value;
        }
    }
}

当我从任何Element类的子类尝试访问属性时,问题就出现了,因为这些属性在基类Section中未设置,例如在元素Solid2D:Element中:

Element类

public abstract class Element
{
    private Section _section;

    public Element(Section section)
    {
        this.section = section;
    }

    public Section section
        {
            get 
            {
                return _section;
            }
            set
            {
                _section = value;
            }
        }
    }
}

实体二维元素类

// Solid2D elements can only have sections of type SectionPlane
public class Solid2D : Element
{
    public Solid2D(SectionPlane section)
        : base(section)
    {
    }

    public void Calc()
    {
        double t = section.t;    // This results in error 'Section' does not contain a definition for 't' and no extension method 't' accepting a first argument of type 'Section' could be found (are you missing a using directive or an assembly reference?)
    }
}

Bar Element

// Bar elements can only have sections of type SectionExtruded
public class Solid2D : Element
{
    public Solid2D(SectionExtruded section)
        : base(section)
    {
    }

    public void Calc()
    {
        double A = section.A;    // This results in error 'Section' does not contain a definition for 'A' and no extension method 'A' accepting a first argument of type 'Section' could be found (are you missing a using directive or an assembly reference?)
    }
}

有没有办法在不将我的属性t包含在基类Section中的情况下访问它?这将非常有帮助,因为我将使用的并不是所有部分都具有相同的属性。


要访问SectionPlane属性,您必须首先将对象类型转换为SectionPlane。Tim S.最先提出了这个问题,但Olivier Jacot-Descombes的帖子更加清晰明了。 - Trisped
几周前我也有同样的问题(http://stackoverflow.com/questions/10804578/design-pattern-for-specialized-properties-in-subclasses),我必须说你比我给出了更好的解释。无论如何,我的解决方案是在`Solid2D`中添加一个字段`SectionPlane sectionPlane并在构造函数中初始化它。在我的情况下,这已经足够了,因为它是只读的。您可能需要重写属性section`(setter)。 - Paul B.
4个回答

7

由于您知道它只能是一个SectionPlane,所以可以将其转换

double t = ((SectionPlane)section).t;

如果您不确定自己是否拥有正确类型的某个部分,可以使用 as 关键字。

double t = 0;
var sectionPane = section as SectionPlane;
if (sectionPane != null) {
    t = sectionPane.t;
}

as 如果尝试将一个对象转换为不兼容类型时,并不会抛出异常,而是返回 null

或者您可以进行简单的测试。

double t = 0;
if(section is SectionPlane) {
    t = ((SectionPlane)section).t;
}

但是这种方式不如使用as优雅,因为你需要测试类型并强制转换它;但是强制转换会在内部再次进行此测试。
使用C# 7.0引入的新模式匹配,你可以这样写:
double t = 0;
if(section is SectionPlane sp) {
    t = sp.t;
}

但是如果您必须执行此测试,问题在于,您的方法是否符合面向对象的原则。如果将Calc方法移至抽象类Section,并让每个类执行自己的计算,则不需要进行类型测试或强制转换。

Section中:

public abstract void Calc();

SectionPlane
public override void Calc()
{
    var x = t;
}

...

section.Calc();  // No casting or type test required.

但那只是一个补丁,而不是最佳建模方式。但是,如果不知道“t”实际代表什么,很难确定更好的模型。 - Illuminati
谢谢!之前尝试过转换,但错过了一些括号,这才有了魔力 =) - sehlstrom

1
我会建议将您的属性“t”放在Section基类中,如果它属于那里的话。

0

以下是几个选项:

  1. Element.section 更改为 SectionPlane
  2. Calc() 中将 section 强制转换为 SectionPlane
  3. t 添加到 Section 中。
  4. 创建一个接口(例如 IHasT),该接口具有 t 属性,使 SectionPlane 实现此接口,并将 Element.section 更改为 IHasT
  5. (如果适用)将 public abstract class Element 更改为 public abstract class Element<T> where T : Section,将 section 更改为类型 T,并使 Solid2D : Element<SectionPlane>

1
谢谢您的回复!
  1. 不可能,因为并非所有元素都会使用SectionPlane。
  2. 我已经尝试过了,但没有成功。
  3. 正如我所提到的,这不是我想要的。
  4. 您能开发这个选项吗?我不明白如何将“Element.section”更改为“IHasT”。
  5. 我会尝试并查看这对代码的其余部分产生什么影响。
- sehlstrom
它们是独立的可能性,而不是单一解决方案的有序列表,因此也要查看2-5。 - Tim S.

0
如果你知道元素继承者将使用的部分类型,我会将元素基类设置为通用类:
 public abstract class Element<SectionType>
     where SectionType:Section
 {
    //....
 }

您可以使用基类来包含默认元素类型:
 public abstract class Element:Element<Section>
 {
    //....
 }

已知元素可以继承强类型:

 public class Solid2D : Element<SectionPlane>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接