C# 访问父级中子级的静态成员
C# access children's static member in parent
我有一个 class Foo,它是许多其他 class 的基础 class,例如 Bar 和 Baz,我想在 Foo 中使用Bar和Baz中的静态成员,如下图:
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;
}
我能想到的唯一解决方案是将所有字段包装在一个容器中,为每个对象添加一个额外的标识符,然后使用函数 return 字段,就像这样
Bar : Foo{
public readonly int id = 0;
public static Wrapper wrapper;
}
public Wrapper GetWrapper(int id){
switch(id){
case 0:
return Bar.wrapper;
}
}
但是,如您所见,我需要维护一个额外的 class 和函数,我不想让我的代码碎片化。还有其他选择吗?
编辑
您所要求的,即从基 class 访问子 class 中的 static
或 const
值在技术上是可行的,但这样做会违反良好 SOLID OO 设计的原则。此外,由于您将需要特定子 class 的实例,以便能够 'reason over' 子 class 的类型以获得适当的 field1
,静态地解决这个问题毫无意义。
相反,这里更常见、更简洁的方法是使用 subtype polymorphicism,这将允许在基础 class 中调用方法,或在外部 class 中调用方法,根据 subclass 访问 'field1' 的适当值。这允许控制值 returned 保留在适当的 subclasses 中(即按照你的话,代码不会变成 "fragmented")。
使用subclass多态的替代方案(推荐)
子class 多态方法(即使用 virtual/abstract
和 override
关键字)将允许您封装可针对每个自定义的值(或对象)的检索子class。在这里,抽象在概念上保持在 "give me an integer value",然后 'how' 到 return 的子 class 特定实现可以从调用者那里抽象(隐藏)值。此外,通过将基础 属性 标记为 abstract
,您将强制所有子 class 实现 属性,这样就不会忘记提供值的要求关于。
即我会推荐这样的多态方法:
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(); }
}
}
如果基础上没有其他可重用的具体方法class Foo
,那么您也可以将抽象建模为接口,效果相同:
public interface IFoo
{
int Result { get; }
}
不用多态性解决这个问题(不推荐)
任何编译时尝试访问 subclasses 上的静态字段通常需要代码在某处切换(或映射)subclass 实例的实际类型,例如:
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,因为每次添加新的子 class 时,都需要更改 result1
方法以适应新的 class.
我建议使用抽象函数而不是静态成员。
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;}
}
您可以将构造函数参数添加到您的 Foo
class 中,它可以从继承者那里传递,因此您不需要额外的 classes 也可以减少耦合
public class Foo
{
private readonly int _field1;
public Foo(int field1)
{
_field1 = field1;
}
}
或者您可以完全从继承类型使用它,因为 static/const 成员是 class 类型
的成员
public class Foo
{
public result1
{
get
{
return Bar.field1;
}
}
}
但这会降低您的代码的灵活性和耦合度。
您还可以选择使用虚拟属性,您可以在派生 classes 中实现并在基础中使用:
public class Foo
{
public virtual int Field { get { return 0; } }
}
您可以使用 virtual
并在每个子 class
中覆盖 result1
,而不是像其他答案建议的那样使 Foo
抽象
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
到 return 除了 0 你可以给它另一个值
public class Foo
{
public virtual int result1 { get; } = -1;
}
当我回答自己的问题时,我总是觉得自己像个混蛋...但没有看到我所期待的,所以我不妨分享一下经过一夜的思考后得到的结果。
我不想计算abstract/virtual的原因是因为有很多子class,而且所有子class的公式都是一样的。我只是拒绝重复输入相同的代码 10-20 次。
也不能使静态字段成为非静态字段,因为它们应该可以在 class 级别访问,而且它们可以变大,并且它们对所有实例都是相同的。
我能想到的最小化代码片段的唯一解决方案是这样的
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;
}
}
所以现在每个实例都需要保存一个额外的引用,但是我不需要保留一个函数。包装器保留在基础 class 中,因此碎片较少。
我有一个 class Foo,它是许多其他 class 的基础 class,例如 Bar 和 Baz,我想在 Foo 中使用Bar和Baz中的静态成员,如下图:
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;
}
我能想到的唯一解决方案是将所有字段包装在一个容器中,为每个对象添加一个额外的标识符,然后使用函数 return 字段,就像这样
Bar : Foo{
public readonly int id = 0;
public static Wrapper wrapper;
}
public Wrapper GetWrapper(int id){
switch(id){
case 0:
return Bar.wrapper;
}
}
但是,如您所见,我需要维护一个额外的 class 和函数,我不想让我的代码碎片化。还有其他选择吗?
编辑
您所要求的,即从基 class 访问子 class 中的 static
或 const
值在技术上是可行的,但这样做会违反良好 SOLID OO 设计的原则。此外,由于您将需要特定子 class 的实例,以便能够 'reason over' 子 class 的类型以获得适当的 field1
,静态地解决这个问题毫无意义。
相反,这里更常见、更简洁的方法是使用 subtype polymorphicism,这将允许在基础 class 中调用方法,或在外部 class 中调用方法,根据 subclass 访问 'field1' 的适当值。这允许控制值 returned 保留在适当的 subclasses 中(即按照你的话,代码不会变成 "fragmented")。
使用subclass多态的替代方案(推荐)
子class 多态方法(即使用 virtual/abstract
和 override
关键字)将允许您封装可针对每个自定义的值(或对象)的检索子class。在这里,抽象在概念上保持在 "give me an integer value",然后 'how' 到 return 的子 class 特定实现可以从调用者那里抽象(隐藏)值。此外,通过将基础 属性 标记为 abstract
,您将强制所有子 class 实现 属性,这样就不会忘记提供值的要求关于。
即我会推荐这样的多态方法:
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(); }
}
}
如果基础上没有其他可重用的具体方法class Foo
,那么您也可以将抽象建模为接口,效果相同:
public interface IFoo
{
int Result { get; }
}
不用多态性解决这个问题(不推荐)
任何编译时尝试访问 subclasses 上的静态字段通常需要代码在某处切换(或映射)subclass 实例的实际类型,例如:
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,因为每次添加新的子 class 时,都需要更改 result1
方法以适应新的 class.
我建议使用抽象函数而不是静态成员。
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;}
}
您可以将构造函数参数添加到您的 Foo
class 中,它可以从继承者那里传递,因此您不需要额外的 classes 也可以减少耦合
public class Foo
{
private readonly int _field1;
public Foo(int field1)
{
_field1 = field1;
}
}
或者您可以完全从继承类型使用它,因为 static/const 成员是 class 类型
的成员public class Foo
{
public result1
{
get
{
return Bar.field1;
}
}
}
但这会降低您的代码的灵活性和耦合度。
您还可以选择使用虚拟属性,您可以在派生 classes 中实现并在基础中使用:
public class Foo
{
public virtual int Field { get { return 0; } }
}
您可以使用 virtual
并在每个子 class
result1
,而不是像其他答案建议的那样使 Foo
抽象
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
到 return 除了 0 你可以给它另一个值
public class Foo
{
public virtual int result1 { get; } = -1;
}
当我回答自己的问题时,我总是觉得自己像个混蛋...但没有看到我所期待的,所以我不妨分享一下经过一夜的思考后得到的结果。
我不想计算abstract/virtual的原因是因为有很多子class,而且所有子class的公式都是一样的。我只是拒绝重复输入相同的代码 10-20 次。
也不能使静态字段成为非静态字段,因为它们应该可以在 class 级别访问,而且它们可以变大,并且它们对所有实例都是相同的。
我能想到的最小化代码片段的唯一解决方案是这样的
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;
}
}
所以现在每个实例都需要保存一个额外的引用,但是我不需要保留一个函数。包装器保留在基础 class 中,因此碎片较少。