簡體   English   中英

為什么 C# 11 編譯器拒絕它接受的泛型參數作為相同類型賦值的來源?

[英]Why does the C# 11 compiler reject a generic parameter that it accepts as the source of an assignment to the same type?

在嘗試讓 C# 編譯器完成盡可能多的工作時,我通常最終會使用(有些人可能會說濫用)通用性。

我經常發現一種特殊情況,但我無法解釋原因。 如果有一個類似於Eric Lippert對這個類似問題的精彩回答的解釋會很棒 - 但據我所知 - 問題: https://stackoverflow.com/a/17440148/257372

我已經修改了真實類的名稱以使用 Animal 以便它與上面的答案相匹配。 我還刪除了所有方法和任何其他不必要的細節,以使事情盡可能簡單。

public interface IAnimal { }

public interface IAnimalOperationResult<out TAnimal> where TAnimal : IAnimal { }

public record DefaultSuccessfulResult<TAnimal>() : IAnimalOperationResult<TAnimal> where TAnimal : IAnimal;

public abstract class AnimalHandler<TAnimal, TSuccessfulAnimalOperationResult> where TAnimal : IAnimal
    where TSuccessfulAnimalOperationResult : IAnimalOperationResult<IAnimal> { }

// The compiler complains here with the following message:
// Error CS0311: The type 'DefaultSuccessfulResult<TAnimal>' cannot be used as type parameter 'TSuccessfulAnimalOperationResult' in the generic type or method 'AnimalHandler<TAnimal, TSuccessfulAnimalOperationResult>'.
// There is no implicit reference conversion from 'DefaultSuccessfulResult<TAnimal>' to 'IAnimalOperationResult<IAnimal>'
public class AnimalHandlerWithDefaultSuccessfulResult<TAnimal> : AnimalHandler<TAnimal, DefaultSuccessfulResult<TAnimal>>
    where TAnimal : IAnimal { }

錯誤消息說沒有從“ DefaultSuccessfulResult<TAnimal> ”到“ IAnimalOperationResult<IAnimal> ”的隱式引用轉換

根據編譯器,這是不正確的,因為它接受以下代碼:

public record Dog() : IAnimal;

[Fact]
public void CanAssignValues()
{
    DefaultSuccessfulResult<Dog> source = new();

    // This assignment requires the same implicit reference conversion the compiler claims doesn't exist.
    // However, in this instance, the compiler accepts it.
    IAnimalOperationResult<IAnimal> target = source;
}

我顯然錯過了什么,但是什么?

簡而言之 - 添加class通用約束:

public class AnimalHandlerWithDefaultSuccessfulResult<TAnimal> : AnimalHandler<TAnimal, DefaultSuccessfulResult<TAnimal>>
    where TAnimal : class, IAnimal { }

原因是僅引用類型支持 C# 中的差異。 來自generics 方差的文檔:

差異僅適用於引用類型; 如果為變體類型參數指定值類型,則該類型參數對於生成的構造類型是不變的。

您將能夠通過將Dog記錄更改為值類型(使用 C# 10 的記錄結構)來“確認”該案例:

public record struct Dog() : IAnimal; 

DefaultSuccessfulResult<Dog> source = new();
// Following produces compiler error:
// Cannot implicitly convert type 'DefaultSuccessfulResult<Dog>' to 'IAnimalOperationResult<IAnimal>'. 
// An explicit conversion exists (are you missing a cast?)
IAnimalOperationResult<IAnimal> target = source;

暫無
暫無

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

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