我有一个类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;
}
但是,正如您所看到的,我需要维护一个额外的类和函数,而不是要破坏我的代码。还有其他选择吗?
答案 0 :(得分:1)
修改
您要求的是,即从基类访问子类中的static
或const
值在技术上是可行的,但这样做会违反良好SOLID OO设计的原则。此外,由于您需要一个特定子类的实例,以便能够“推理”子类的类型以获得适当的field1
,所以静态地接近这个问题几乎没有意义。
相反,这里常见的,更清晰的方法是使用subtype polymorphicism,这将允许基类中的调用方法或外部类中的方法,以基于'field1'访问适当的值在子类上。这允许控制返回的值保留在适当的子类中(即按照你的说法,代码不会变成“碎片”)。
使用子类多态的替代解决方案(推荐)
子类多态方法(即使用virtual/abstract
和override
关键字)将允许您封装对每个子类可自定义的值(或对象)的检索。这里,抽象在概念上仍然是“给我一个整数值”,然后可以从调用者中抽象(隐藏)“如何”返回值的子类特定实现。此外,通过将基本属性标记为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;
}
}
所以现在每个实例都需要额外引用,但是我不需要保留一个函数。包装器保留在基类中,因此碎片较少。