簡體   English   中英

通用類型約束檢查

[英]Generic type constraint checking

是否有可能在調用這些方法之一時編寫在編譯或運行時(即以任何方式)失敗的東西?

public static void Register<TInterface, TImplementation>()
    where TImplementation : class, TInterface
{
}
public static void RegisterRestrictive<TInterface, TImplementation>()
    where TInterface : class
    where TImplementation : class, TInterface
{
}

以下將通過兩個例子:

public interface IInterface
{
}

public class Implementation : IInterface
{
}


public void Test()
{
    Register<IInterface, Implementation>();
    RegisterRestrictive<IInterface, Implementation>();
}

我不認為是,因為你不能擴展結構?

因為這個https://github.com/aspnet/DependencyInjection/pull/624

問題是,據我了解:

class C<T, U> where T : class, U where U : class { }
class D<T, U> where T : class, U { }

是否存在對D而言合法的結構對C不合法

如果UT封閉類型 ,則不是。 也就是說,其中沒有類型參數的類型。 正如Jon Hanna的回答指出的那樣, 開放式可能會導致問題:

class N<T, U> where T : class, U { C<T, U> c; D<T, U> d; }

D的限制沒有得到滿足,因此這種結構是非法的。

對於封閉類型的類型參數,我們可以推斷如下:

C ,約束要求U是引用類型。

DT可以是類,接口,委托或數組。 在任何情況下, U必須是相同T ,或基類的T ,或東西T可轉化為經由(可能變體)隱式引用轉換。 無論如何, U是參考類型。

請注意,無論是C#編譯器,CLR驗證器還是JIT編譯器都不需要推斷出U始終是一個引用類型! 例如,在這種情況下,C#編譯器會對U用法生成不必要的裝箱指令,即使您和我知道U不會是正在構造的值類型。

這可能導致U被裝箱然后立即取消裝箱的情況,以及我最后一次檢查 - 這是,呃,十年前 - 抖動沒有為該場景生成最佳代碼。 毫無疑問,自從我上次檢查以來,抖動已被重寫了一次或多次,你可能不應該接受我的話。

這里的好習慣是將約束放在那里並拼出來。


一些有趣的相關事實:

你可以通過拉扯類似的惡作劇來進入類似的情況

class B<T> { public virtual void M<U>(U u) where U : T {} }
class D : B<int> { public override void M<U>(U u) { } }

請注意,C#不允許您重新聲明約束,現在where U : int 但你不能用除int之外的任何東西做M的泛型構造。

這可能導致IL生成中的一些真正奇怪的場景,因為CLR具有記錄不良的規則,因此它不允許類型參數的“已知為參考類型”的性能在虛擬覆蓋。 我為這些方法重新編寫了codegen,試圖在放棄並返回C#2所做的任何事情之前嘗試獲得可以編譯,傳遞驗證器和jit高效幾次的內容。

是否有可能在調用這些方法之一時編寫在編譯或運行時(即以任何方式)失敗的東西?

是的,這在編譯時失敗了:

public static void CallThem<TA, TB>()
    where TB : class, TA
{
    Register<TA, TB>();         // Fine
    RegisterRestrictive<TA, TB>(); // CS0452
}

沒有一對與TInterfaceTImplementation僅匹配其中一個的具體類型,但調用方法的類型參數類型當然可以,而類型參數類型是我們在設計API時需要考慮的類型以及具體類型。

約束不涉及其他約束的推斷。

暫無
暫無

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

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