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

Cannot pass a non-nullable object as a parameter that accepts nullalble

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

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

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

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

Argument of type 'Dictionary< string, object>' cannot be used for parameter 'nullable' of type 'IDictionary' in '...' due to differences in the nullability of reference types

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

这与通用类型参数 covariance/contravariance problem because IDictionary supports "in and out" 数据移动(与 IReadOnlyDictionary 相比,后者是 "out" 容器)是同一个问题。

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

// 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 以实现逆变(或协变,我忘了哪个是哪个)它应该工作。

请注意,只有接口和委托可以使用 inout 注释其泛型类型参数,而具体类型(包括抽象 类)不能。这不是问题,前提是将使用泛型类型的程序(期望类型参数变化)编程为使用接口而不是具体类型。

在 C# 7.0 之前,您不需要这个 object? 因为类型对象接受可为 null 的值,与字符串相同。例如,如果它是 int 那么你需要这样做 IDictionary<string, int?>