动态返回类型依赖于C#中的子类?

时间:2016-05-30 13:04:12

标签: c# oop abstract

我想用抽象的getter Command声明一个基类GetValue。然后我将其子类化为TalkCommandSpendCommand,例如。

这两个类都必须实现GetValue,但是,我希望TalkCommandstring返回GetValue类型(要说什么?),我希望{{1}返回SpendCommand类型。 (花多少钱?)

我不知道如何在int基类中编写它。这种设计在C#中是否可行?

3 个答案:

答案 0 :(得分:3)

In addition to Manfred's answer,我想给你一个进一步的提示。

虽然泛型为您提供了定义GetValue返回类型的有用工具,但您无法执行以下向上转换:

abstract class Command<T>
{
    public abstract T GetValue();
}

class TalkCommand : Command<string>
{
    public override string GetValue()
    {
        return "Test";
    }
}

// TalkCommand isn't Command<object>
Command<object> cmd = new TalkCommand();

我不会将您的命令定义为抽象类,而是开始将其定义为covariance的接口:

public interface ICommand<out T>
{
    T GetValue();
}

整个抽象类可以实现ICommand<out T>

abstract class Command<T> : ICommand<T>
{
    public abstract T GetValue();
}

现在,您可以将ICommand<string>的实施转发为ICommand<object>

ICommand<string> cmd = new TalkCommand();
ICommand<object> cmd2 = cmd;

这很好,因为你可以获得两个世界中最好的一面:

  • 您的命令具有强大的返回类型。
  • 您的命令通常可以视为ICommand<object>的实现,这可以让您在某些不知道要提供的泛型参数的情况下调用GetValue并返回object根本不需要它。

答案 1 :(得分:2)

如果返回类型必须根据子类而不同,那么最好不要在基类中使用此方法。

首先拥有基类型的想法是让你以统一的方式处理所有子类。一个人应该能够写

Command cmd = ... // One of subclasses
<some-type> val = cmd.GetValue();

并将<some-type>替换为实际类型。但是,在您的情况下,objectint除了string之外没有共同的基本类型,因此使用不同的返回类型变得毫无意义。

您可以将GetValue实现为通用,如下所示:

abstract class Command {
    abstract T GetValue<T>();
    ...
}

但是这需要调用者将所需类型作为GetValue的类型参数传递,这将使基类中GetValue的目的失效。

可能的解决方法:一种让来电者远离了解类型的方法就是访问者 - 建立一个允许Command&#34;推送&#34;调用者的值,如下所示:

IValueGetter {
    void SetInt(int v);
    void SetString(string v);
}

abstract class Command {
    abstract void GetValue(IValueGetter g);
}
class TalkCommand {
    override void GetValue(IValueGetter g) {
        g.SetString("hello");
    }
}
class BuyCommand {
    override void GetValue(IValueGetter g) {
        g.SetInt(123);
    }
}

现在调用者可以与Command进行交互,而不知道其GetValue的类型。产生int的命令会回调SetInt,而产生string的命令会回拨SetString

答案 2 :(得分:1)

仅当您的基类frontend是通用的或您不介意使用Command

通用示例

如果您始终使用已知的实例类型,这将是最好的方法,因为您可以使用所需的数据类型而不需要进行转换。

object

对象示例

这是一种非常通用的方法,几乎​​是WPF对abstract class Command<T> { public abstract T GetValue(); } class TalkCommand : Command<string> { public override string GetValue() { return "Test"; } } class SpendCommand : Command<int> { public override int GetValue() { return 1234; } } 以及DependencyPropertiesIList等非通用集合的处理方式。

IEnumerable

混合示例

如果您希望能够同时使用它们,则需要一个非泛型基类并从中继承另一个抽象泛型类。

abstract class Command
{
    public abstract object GetValue();
}

class TalkCommand : Command
{
    public override object GetValue()
    {
        return "Test";
    }
}

class SpendCommand : Command
{
    public override object GetValue()
    {
        return 1234;
    }
}