簡體   English   中英

C#使用具有“類類型”返回類型的另一個函數覆蓋抽象類的函數

[英]C# Override an abstract class' function with a different one with a “Class Type” return type

我試圖創建一個基於抽象類的類,並用另一個返回類型為“T”的類覆蓋基類中包含的函數,該類是由類傳遞的類型。

例如:

public abstract class DayInfo
{
    public virtual void GetInfo()
    {
        throw new NotImplementedException();
    }
}

public class DayInfo<T> : DayInfo
{
    private T info;
    public DayInfo(T data)
    {
        info = data;
    }

    public T GetInfo() // << This
    {
        return info;
    }
}

例子:

1

DayInfo info = new DayInfo<String>("Blah");
String stuff = info.GetInfo();

2

DayInfo info = new DayInfo<int>(25);
int stuff = info.GetInfo();

沒有辦法實現這個目標?

編輯1:我忘了確切地說我沒有在基類中使用類傳遞類型,因為我希望能夠將它用作泛型類型,而不必定義任何類型。

例如:

public SortedDictionary<int, DayInfo> Data = new SortedDictionary<int, DayInfo>();

編輯2:

此外,基類中虛函數的要點是,如果訪問GetInfo()函數但未覆蓋子類,它將使子類拋出異常。

這是實現目標的方法:

public abstract class DayInfoA<T>
{
    public virtual T GetInfo()
    {
        .......
    }
}

public class DayInfoB<T> : DayInfoA<T>
{
    private T info;
    public DayInfoB(T data)
    {
        info = data;
    }

    public override T GetInfo() // << This
    {
      .........
    }
}

並像這樣使用它:

        DayInfoB<int> info = new DayInfoB<int>(25);
        int stuff = info.GetInfo();

為什么不將GetInfo()聲明為dynamic 這樣鑄造應該是自動的。 唯一的缺點是您丟失了編譯器斷言,如果存儲GetInfo()值的變量無法執行GetInfo() ,則會拋出運行時錯誤。

例如:

public abstract class DayInfo {
    public abstract dynamic GetInfo();
}

public class DayInfo<T> : DayInfo {
    private readonly T _info;
    public DayInfo(T info) {
        _info = info;
    }
    public override dynamic GetInfo() {
        return _info;
    }
}

你也可以聲明類似GetInfo<T>(ref T result) ,這樣你就可以省略方法調用中的T類型並讓編譯器在運行時推斷它,唯一的缺點就是你應該傳遞變量來存儲結果作為參數而不是由方法返回。

不,不像它看起來像你想要它(假設你不想或不能改變基類聲明)。 為了使函數解析為多態調用,您需要具有相同的簽名和返回類型。 否則它不會以多態方式解析函數,它只會調用函數的基類版本,因為它是您看到的調用(並且您為實例分配的變量屬於基類類型)。

你可以這樣做,但它很難看:

        DayInfo info = new DayInfo<String>("Blah");
        String stuff = ((DayInfo<string>)info).GetInfo();

不,因為這些功能與不同的功能簽名不匹配。

你可以做的是這樣定義:

public abstract class DayInfo
{
    public virtual object GetInfo()
    {
        throw new NotImplementedException();
    }
}

在這樣的派生類中:

public object GetInfo() // << This
{
    return info;
}

然后它們都具有相同的簽名,並且多態性將匹配。 但是,另一方面需要演員:

DayInfo info = new DayInfo<int>(25);
int stuff = (int)info.GetInfo();

編輯:除非有更多內容,否則我會把它變成一個接口,或者如果GetInfo真的什么也沒做,那么GetInfo純粹抽象的。

public abstract object GetInfo();

這可以使用NVI模式生成

public abstract class DayInfo
{
  protected virtual void GetInfoCore() {
    throw new NotImplementedException();
  }

  // or
  // protected abstract void GetInfoCore();

  public void GetInfo() {
    GetInfoCore();
  }
}

public class DayInfo<T> : DayInfo
{
  private T info;

  public DayInfo(T data) {
    info = data;
  }

  public new T GetInfo() { // << This
    return info;
  }

  protected override void GetInfoCore() {
    GetInfo();
  }
}

您可以創建一個協變接口,而不是基類,或者除了基類之外:

void Main()
{
    IDayInfo dayInfo = new DayInfo<string>("hi!");
    object info = dayInfo.GetInfo(); //info == "hi!"
}
public interface IDayInfo
{
    object GetInfo();
}
public interface IDayInfo<out T> : IDayInfo
{
    new T GetInfo();
}

public class DayInfo<T> : IDayInfo<T>
{
    private T info;
    public DayInfo(T data)
    {
        info = data;
    }

    public T GetInfo()
    {
        return info;
    }
    object IDayInfo.GetInfo()
    {
        return this.GetInfo();
    }
}

(有關協方差/逆變的信息,請參閱通用接口中的差異

請注意,在此示例中, object info (在Main中的第二行)與您在不進行強制轉換的情況下一樣精確。 一旦你將DayInfo<string>對象存儲在IDayInfo<object>變量/字段中,就像我一樣(並且你想在你的字典中做),從某種意義上說, string的強類型是被遺忘的,不能無需演員表即可恢復。

更新:添加了IDayInfo界面。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM