不能将不可为 null 的对象作为接受 nullalble 的参数传递

Ily*_*dik 1 c# nullable-reference-types

我有这个简单的代码,它会生成一个警告:

private void MyMethod()
{
    IDictionary<string, object> notNullable = new Dictionary<string, object>();
    Test(notNullable);
}

private void Test(IDictionary<string, object?> nullable)
{
}
Run Code Online (Sandbox Code Playgroud)

当我尝试编译时收到此警告(尽管它确实适用于!):

由于引用类型的可为空性的差异,“Dictionary<string, object>”类型的参数不能用于“...”中“IDictionary”类型的参数“nullable”

现在我可以看到相反的问题,但是我将不可为空的参数发送到可空参数是怎么回事?只是 C# 编译器的限制,或者可能是一个错误?

Dai*_*Dai 5

这与泛型类型参数协方差/逆变问题相同,因为IDictionary支持数据的“进出”移动(与IReadOnlyDictionary“出”容器相比)。

它的原因 不编译 发出警告是因为它允许这样做:

// This code requires a C# 8.0 compiler!

private void MyMethod()
{
    IDictionary<String,Object> cannotContainNulls = new Dictionary<String,Object>();

    Test( cannotContainNulls );

    assert( cannotContainNulls[ "this has a null value" ] == null ); // this shouldn't be possible!
}

private void Test( IDictionary<String,Object?> canContainNulls )
{
    canContainNulls.Add( key: "this has a null value", value: null );
}
Run Code Online (Sandbox Code Playgroud)

如果您更改Test方法以接受IReadOnlyDictionary(其中TValue标记out为逆变(或协方差,我忘记了哪个),它应该可以工作。

请注意,只有接口和委托可以用inand注释它们的泛型类型参数out,而具体类型(包括抽象类)不能。如果使用期望类型参数变化的泛型类型的程序被编程为使用接口而不是具体类型,那么这不是问题。