首页 > 解决方案 > 不能将不可为空的对象作为接受 nullalble 的参数传递

问题描述

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

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

private void Test(IDictionary<string, object?> nullable)
{
}

当我尝试编译时收到此警告(但它确实可以使用!):

由于引用类型的可空性不同,“...”中“IDictionary”类型的参数“可空”不能使用“字典<字符串,对象>”类型的参数

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

标签: c#nullable-reference-types

解决方案


这与泛型参数协方差/逆变问题是相同的问题,因为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 );
}

如果你改变你的Test方法来接受一个IReadOnlyDictionary(其中TValue标记out为逆变(或协方差,我忘了哪个是哪个)它应该起作用。

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


推荐阅读