繁体   English   中英

动态返回类型取决于C#中的子类?

[英]Dynamic return type that depends on subclass in C#?

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

这两个类都必须实现GetValue ,但是,我想让TalkCommand返回GetValue string类型( TalkCommand什么?),我想让SpendCommand返回int类型。 (要花多少钱?)

我不知道如何在Command基类中编写此代码。 这种设计在C#中可行吗?

除了曼弗雷德(Manfred)的答案,我想给你一个提示,进一步说明。

虽然泛型为您提供了定义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();

与其将命令定义为抽象类,不如将其定义为具有协方差的接口:

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

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

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

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

并将<some-type>替换为实际类型。 但是,在您的情况下,除了intstring object以外,没有其他通用的基本类型,因此拥有不同的返回类型变得毫无意义。

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

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

但这要求调用者将所需的类型作为GetValue类型参数传递,这将使在基类中具有GetValue的目的GetValue

可能的解决方法一种使调用者不知道类型的方法是访客-创建一个接口,使Command将值“推”到调用者中,如下所示:

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);
    }
}

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

仅当您的基类Command是通用的,或者您不介意使用object

通用示例

如果您始终使用已知的实例类型,那么这将是最好的方法,因为您可以无需转换就可以使用所需的数据类型。

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;
    }
}

对象实例

这是一种非常通用的方法,几乎​​是WPF对DependencyProperties和非通用集合(如IListIEnumerable所做的工作。

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;
    }
}

混合范例

如果要同时使用两者,则需要一个非泛型基类并从中继承另一个抽象泛型类。

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM