C#访问父级的子级静态成员

时间:2017-08-20 08:39:30

标签: c# inheritance static-members

我有一个类Foo,它是很多其他类(如Bar和Baz)的基类,我想使用Bar和Baz中的静态成员在Foo中进行一些计算,如下所示:

with Table2Data as
 (
  SELECT Id , Name ,row_number() over(partition by Id order by number) rowNumber FROM Table2 
 )
 select t1.* ,t2.name from table1 t1 
 inner join Table2Data t2 on t1.Id=t2.Id and t2.rowNumber=1 

我能想到的唯一解决方案是将所有字段包装在容器中,为每个对象添加额外的标识符,并使用函数返回字段,如下所示

public class Foo{
    public result1 {
         get{
             return field1;
         }
    }
}

public class Bar : Foo{
    public const int field1 = 5;
}

public class Baz : Foo{
    public const int field1 = 10;
}

但是,正如您所看到的,我需要维护一个额外的类和函数,而不是要破坏我的代码。还有其他选择吗?

5 个答案:

答案 0 :(得分:1)

修改

您要求的是,即从基类访问子类中的staticconst值在技术上是可行的,但这样做会违反良好SOLID OO设计的原则。此外,由于您需要一个特定子类的实例,以便能够“推理”子类的类型以获得适当的field1,所以静态地接近这个问题几乎没有意义。

相反,这里常见的,更清晰的方法是使用subtype polymorphicism,这将允许基类中的调用方法或外部类中的方法,以基于'field1'访问适当的值在子类上。这允许控制返回的值保留在适当的子类中(即按照你的说法,代码不会变成“碎片”)。

使用子类多态的替代解决方案(推荐)

子类多态方法(即使用virtual/abstractoverride关键字)将允许您封装对每个子类可自定义的值(或对象)的检索。这里,抽象在概念上仍然是“给我一个整数值”,然后可以从调用者中抽象(隐藏)“如何”返回值的子类特定实现。此外,通过将基本属性标记为abstract,您将强制所有子类实现该属性,因此不会忘记提供值的要求。

即。我会推荐像这样的多态方法:

public abstract class Foo
{
    public abstract int Result { get;  }
}

public class Bar : Foo
{
    // This is implementation specific. Hide it.
    private const int field1 = 5;

    public override int Result 
    { 
        get { return field1; }
    }
}

public class Baz : Foo
{
    public override int Result 
    { 
        // No need for this implementation to be a constant ...
        get { return TheResultOfAReallyComplexCalculationHere(); }
    }
}

如果基类Foo上没有其他可重用的具体方法,那么您也可以将抽象建模为接口,具有相同的效果:

public interface IFoo
{
    int Result { get;  }
}

在没有多态性的情况下解决此问题(不推荐)

任何编译时尝试访问子类上的静态字段通常都需要代码在某处切换(或映射)子类实例的实际类型,例如:

public class Foo
{
    public int result1 
    {
         get
         {
             switch(this.GetType().Name)
             {
                case "Bar":
                    return Bar.field1;
                case "Baz":
                    return Baz.field1;
                default:
                    return 0;
             }
         }
    }

    public void MethodRequiringValueFromSubclass()
    {
        Console.WriteLine(result1);
    }
}

public class Bar : Foo
{
    public const int field1 = 5;
}

public class Baz : Foo
{
    public const int field1 = 10;
}

此处的问题是违反了Open and Closed principal,因为每次添加新的子类时,都需要更改result1方法以适应新类。

答案 1 :(得分:0)

我建议使用抽象函数,而不是使用静态成员。

public abstract class Foo{
    public result1 {
         get{
             return get_field1();
         }
    }
    protected abstract int get_field1();
}

public class Bar : Foo{
    public const int field1 = 5;
    protected override int get_field1() { return field1;}
}

public class Baz : Foo{
    public const int field1 = 10;
    protected override int get_field1() { return field1;}
}

答案 2 :(得分:0)

你可以在你的Foo类中添加构造函数参数,这些参数可以从继承者传递,因此你也不需要额外的类,你也会减少耦合

public class Foo
{
    private readonly int _field1;
    public Foo(int field1)
    {
         _field1 = field1;
    }
}

或者您可以完全使用继承者类型,因为static / const成员是类类型

的成员
public class Foo
{
    public result1 
    {
         get
         {
             return Bar.field1;
         }
    }
}

但这会降低代码的灵活性和耦合度。

您还可以选择使用虚拟属性,您可以在已开发的类中实现并在base中使用:

public class Foo
{
    public virtual int Field { get { return 0; } }
}

答案 3 :(得分:0)

不要像其他答案那样提出Foo摘要,而是可以在每个子类中使用virtual并覆盖result1

public class Foo
{
    public virtual int result1 { get; }
}

public class Bar : Foo
{
    public const int field1 = 5;

    public override int result1
    {
        get { return field1; }
    }
}

public class Baz : Foo
{
    public const int field1 = 10;

    public override int result1
    {
        get { return field1; }
    }
}

如果您希望默认result1返回0以外的其他内容,则可以为其提供另一个值

public class Foo
{
    public virtual int result1 { get; } = -1;
}

答案 4 :(得分:0)

当我回答自己的问题时,我总觉得自己是一个混蛋...但是我没有看到我所期待的东西,所以我也可以分享我在一夜难以置信之后得到的东西。

我不想让计算抽象/虚拟的原因是因为有许多子类,所有这些子公式都是相同的。我只是拒绝重复输入相同的代码10-20次。

无法使静态字段非静态,因为它们应该可以在类级别访问,而且它们可以变大,并且它们对于所有实例都是相同的。

我能想出的最小化代码片段的唯一解决方案是这样的

public class Foo {
    public class Wrapper {
        Fields...
    }
    public Wrapper wrapper; // reference
    public int result1 { get; }
}

public class Bar : Foo {
    public static Wrapper subclassWrapper; // put in the implementation
    public Bar() : base(){
        wrapper = subclassWrapper;
    }
}

所以现在每个实例都需要额外引用,但是我不需要保留一个函数。包装器保留在基类中,因此碎片较少。