簡體   English   中英

將結構作為通用協變參數

[英]Put a struct as a generic covariant parameter

我有一個 Covariant 接口,它位於它的父類型的數組中。 它們在全局定義如下:

//The interface/class
public interface IMyType<out T>{}
public class MyType<T>: IMyType<T>{
    T value;
    MyType<T>(T initialValue){
        value = initialValue;
    }
}

我試過這個:

IMyType< object>[] tt = new IMyType<object>[]
{
    new MyType<String>( "test"), //Works fine
    new MyType<SomeOtherRandomClass>(new SomeOtherRandomClass()),//works fine
    new MyType<Int32>(12)//Doesn't work
};

甚至試圖指定一個結構而不是對象:

IMyType< struct>[] tt = new IMyType<struct>[]//Doesn't work:Incorrect Number of parameter
{
    new MyType<Int32>(12)//Doesn't work
};

僅指定特定結構有效:

IMyType< int>[] tt = new IMyType<int>[]//Does work
{
    new MyType<Int32>(12)//Does work
};

那么為什么這不起作用呢? 有沒有辦法讓它工作?

Interface<ValueType>轉換為Interface<object>作為協變轉換是完全不可能的。

這樣做的原因是 JITter 必須為每個值類型編譯一個單獨的類版本(因為值類型具有不同的形狀),因此它不能將它轉換為任何其他通用實例化。

方差僅適用於引用類型,因為引用都是相同的,因此 JITted 方法可以在不同的類型參數之間共享。

您最好的解決方案可能是編寫一個封裝結構的包裝類:

public class StructContainer<TStruct> where TStruct : struct
{
    TStruct value;
    public StructContainer(TStruct initialValue)
    {
        value = initialValue;
    }
}

那么你可以這樣做:

IMyType<object>[] tt = new IMyType<object>[]
{
    new MyType<String>("test"), //Works fine
    new MyType<StructContainer<int>>(
        new StructContainer<int>(12)
    ) // compiles now
};

誠然,這犧牲了原始語法的簡單性,並迫使您稍后在需要從集合中提取項目時做一些復雜的事情(如類型檢查)。

另一種選擇是將對象集合和結構集合作為單獨的集合進行跟蹤。 這可能更有意義,因為同樣,一旦您將項目從列表中拉出,您可能需要以不同的方式對待它們。

如果你想完成將具有不同類型參數的泛型類型放入同一個集合中,並且由於 SLaks 提到的原因你不能使用協方差,那么你應該讓泛型類型實現一個非泛型接口:

public interface IMyType<out T> : ISomeBaseInterface {}

var tt = new ISomeBaseInterface[] 
{
    new MyType<String>( "test"), //Works fine
    new MyType<SomeOtherRandomClass>(new SomeOtherRandomClass()),//works fine
    new MyType<Int32>(12)//now it works
};

根據您的其他要求,這可能足夠也可能不夠。

暫無
暫無

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

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