在尝试访问子类成员时使用泛型

时间:2014-03-17 18:24:23

标签: c# .net generics

我有这些对象:

class Order { ... }

class OrderA : Order { public double X; }

class OrderB : Order { public double X; }

class OrderC : Order { public double Y; }

我想做一个接收Order对象的3个子类的方法,如下所示:

private DoSomething<T>(T order) where T : Order
{
    double myValue = order is OrderA || order is OrderB ? (T)order.X : (T)order.Y;

    // DO SOMETHING MORE
}

但我无法编译我的代码,因为“T不包含X的定义...” 这可能吗?

3 个答案:

答案 0 :(得分:4)

这样可行:

double myValue = 
    (order is OrderA) ? ((OrderA)order).X :
    (order is OrderB) ? ((OrderB)order).X :
    (order is OrderC) ? ((OrderC)order).Y;

然而,不得不在通用内部进行这种测试,这样做会破坏使用泛型的目的。

您可以提供DoSomething的不同重载来处理您希望收到的每个案例:

private DoSomething(OrderA order)
{
    double myValue = order.X;
    // DO SOMETHING MORE
}

private DoSomething(OrderB order)
{
    double myValue = order.X;
    // DO SOMETHING MORE
}

private DoSomething(OrderC order)
{
    double myValue = order.Y;
    // DO SOMETHING MORE
}

然后你可能想要把它包裹起来......做更多的事情&#39;在私有方法中使用尽可能多的通用逻辑。

或者,您可以在Order中创建虚拟或抽象方法,如下所示:

class Order {
    public virtual double GetValue() { ... }
}

class OrderA : Order { 
    public double X; 
    public override double GetValue() { return this.X; }
}

class OrderB : Order { 
    public double X; 
    public override double GetValue() { return this.X; }
}

class OrderC : Order { 
    public double Y; 
    public override double GetValue() { return this.Y; }
}

...

private DoSomething(Order order)
{
    double myValue = order.GetValue();
    // DO SOMETHING MORE
}

注意,两种解决方案都不需要使用泛型。

答案 1 :(得分:2)

由于X / Y成员尚未在核心Order类中声明,因此DoSomething方法无法看到它们。当然,您可以将您的订单值强制转换为您想要的类型,但这样做会破坏使用通用方法的目的。

我个人对于泛型有一个经验法则:每当我需要使用泛型类型时,我肯定做错了

如果你需要的是在做更多事情之前获得适当的值,我建议你使用重载方法。这些可以反过来称为&#34;核心&#34;具有适当参数的方法:

private void DoSomething(OrderA order)
{
    DoSomethingMore(order, order.X);
} 

private void DoSomething(OrderB order)
{
    DoSomethingMore(order, order.X);
} 

private void DoSomething(OrderC order)
{
    DoSomethingMore(order, order.Y);
} 

private void DoSomethingMore(Order order, double value)
{
    // do something more
}

答案 2 :(得分:0)

在Order类中定义一个抽象方法并在每个子类中覆盖它。这样,每个类都可以在不抛出订单实例的情况下完成工作。正如@Crono所说,这将破坏仿制药的目的。

//In Order class
public abstract void DoIt(){}

//In OrderSubClass class
public override void DoIt(){
  //Do Something with X or Y
}

//Client code
private void doSomething( Order theOrder){
  theOrder.DoIt();
}

如果处理更复杂,我建议你坚持使用模板方法模式:
Template Method Pattern