簡體   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