【问题标题】:C# Accessing a subclass propertyC# 访问子类属性
【发布时间】:2012-06-19 21:03:44
【问题描述】:

我有几个类,但在从其他类方法访问子类中定义的属性时遇到问题。

我有一个名为 Section 的基类和一些子类,例如SectionPlane : Section。在每个子类中,定义了一组不同的字段和属性(在SectionPlane 中,可以找到私有字段_t 和公共属性t,而在SectionExtruded : Section 中我有私有字段_A 和公共属性´ A´)。

类部分

// 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:

类元素

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 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 的帖子在这件事上要清楚得多。
  • 几周前我有同样的问题 (stackoverflow.com/questions/10804578/…),我必须说你对这个问题的解释比我的好得多。无论如何,我的解决方案是在Solid2D 中添加一个字段SectionPlane sectionPlane 并在构造函数中对其进行初始化。就我而言,这已经足够了,因为它是只读的。您可能需要覆盖属性 section (setter)。

标签: c# .net properties polymorphism


【解决方案1】:

既然你知道它只能是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”实际代表什么的情况下,很难说出更好的模型。
  • 谢谢!之前尝试过施放,但错过了几个起到神奇作用的括号 =)
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    这里有几个选项:

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

    【讨论】:

    • 感谢您的回复! 1. 不可能,因为并非所有元素都会使用截面平面。 2. 我试过这个没有运气。 3. 正如我所提到的,不是我想要的。 4. 你能开发这个选项吗?我不明白如何将Element.section 更改为IHasT 5。将尝试看看这会给其余代码带来什么后果
    • 它们是不同的可能性,而不是单个解决方案的有序列表,所以也请查看 2-5。
    【解决方案4】:

    如果您知道元素继承者将使用的部分类型,我会将元素基类设为泛型:

     public abstract class Element<SectionType>
         where SectionType:Section
     {
        //....
     }
    

    您可以使用基类包含默认元素类型:

     public abstract class Element:Element<Section>
     {
        //....
     }
    

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

     public class Solid2D : Element<SectionPlane>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-24
      • 2019-04-02
      • 1970-01-01
      • 1970-01-01
      • 2017-08-03
      • 1970-01-01
      • 2014-01-14
      • 2019-05-21
      相关资源
      最近更新 更多