CS8766:返回类型中引用类型的可空性与隐式实现的成员不匹配

Joe*_*Joe 2 c# c#-8.0 nullable-reference-types

我在 C# 8.0 项目中启用了可空引用。我还将所有警告设置为错误,以迫使自己解决所有此类警告。但其中之一让我感到困惑。它是一个依赖属性,它返回一个可能有效为空的接口指针。这是属性(在名为“LayerView”的控件内)

private static readonly DependencyProperty ShapeBeingDrawnProperty = DependencyProperty.Register(
    nameof(ShapeBeingDrawn), 
    typeof(IShape), 
    typeof(LayerView),
    new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));

public IShape ShapeBeingDrawn
{
    get => GetValue(ShapeBeingDrawnProperty) as IShape;  // RIGHT SIDE OF "=>" UNDERLINED IN RED
    set => SetValue(ShapeBeingDrawnProperty, value);
}
Run Code Online (Sandbox Code Playgroud)

启用可为空引用时,这会导致对 getter 的警告是可以理解的。get 的整个右侧用红色下划线标出,我收到此构建错误

1>C:\Users\jmole\Documents\Dev\Mobile\Core\Views\LayerView.xaml.cs(429,13,429,16): error CS8766:
Nullability of reference types in return type of 'IShape? LayerView.ShapeBeingDrawn.get' doesn't 
match implicitly implemented member 'IShape ILayerView.ShapeBeingDrawn.get' (possibly because of 
nullability attributes).
Run Code Online (Sandbox Code Playgroud)

首先,他们在谈论什么“隐式”实现的成员?这是一个显式实现的成员。我真的在这里实施它。但除此之外,我试图解决这个问题,因为我已经修复了许多其他此类有效可为空的属性:使属性返回一个可为空的引用

public IShape? ShapeBeingDrawn     // ONLY CHANGE IS HERE
{
    get => GetValue(ShapeBeingDrawnProperty) as IShape; // NOW, JUST "get" IS UNDERLINED IN RED
    set => SetValue(ShapeBeingDrawnProperty, value);
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,这无济于事。我仍然遇到同样的错误,但这次唯一以红色下划线的部分只是 getter 的左侧(“get”一词)。

最后,我能够通过将属性更改回正常引用并在 getter 中使用硬转换来消除此错误

public IShape ShapeBeingDrawn
{
    get => (IShape)GetValue(ShapeBeingDrawnProperty);
    set => SetValue(ShapeBeingDrawnProperty, value);
}
Run Code Online (Sandbox Code Playgroud)

但是现在,任何试图将此属性设置为 null(有效)的代码都会出现编译器错误,我必须解决这个问题。

private void LayerView_OnKeyDown(object sender, KeyEventArgs e)
{
    // Don't do anything if we've disabled shape mouse/touch input.

    if (e.Key != Key.Escape)
        return;

    UnselectAll();
    ShapeBeingDrawn = null;  // COMPILER NO LIKEY
}
Run Code Online (Sandbox Code Playgroud)

那么集成可为空引用和依赖属性的正确方法是什么?我应该#pragma warning disable 围绕这些问题吗?如果可以的话,我想避免这种情况。

Ili*_*hev 5

TL; 博士

出现问题是因为属性在接口中ShapeBeingDrawn被声明为不可为空的引用类型,但在类中它被实现为可以为空的引用类型。因此编译器抱怨类中属性的返回类型与接口中的返回类型不匹配。IShapeILayerViewLayerViewIShape?

为了解决这个问题,我们应该确保接口和类都将属性声明为nullableor non-nullable。如果其中之一的声明不同,那么我们将再次收到编译器错误。


解释

为什么会出现问题?

错误 CS8766:返回类型中引用类型 的可空性'IShape? LayerView.ShapeBeingDrawn.get'与隐式实现的成员不匹配'IShape ILayerView.ShapeBeingDrawn.get'(可能是因为可空性属性)。

从错误信息中我们可以看到有一个ILayerView带有non-nullable属性的接口ShapeBeignDrawn

interface ILayerView
{
    IShape ShapeBeingDrawn { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

以及一个LayerView实现此接口但将属性声明ShapeBeignDrawnnullable

public class LayerView
{
    public IShape? ShapeBeingDrawn
    {
        get => GetValue(ShapeBeingDrawnProperty) as IShape;
        set => SetValue(ShapeBeingDrawnProperty, value);
    }
}
Run Code Online (Sandbox Code Playgroud)

因此接口将属性声明为,non-nullable但类将其实现为nullable。因此编译器抱怨getter类中属性的返回类型与接口中的返回类型不匹配。

题:

首先,他们在谈论什么“隐式”实现的成员?

回答:

当我们声明一个属性时,编译器会为它隐式生成两个方法get_PropertyNameset_PropertyName。因此编译器抱怨隐式实现getter方法的返回类型。


我们应该如何解决问题?

为了解决这个问题,我们应该确保接口和类都将属性声明为nullableor non-nullable。如果其中一个声明不同,那么我们将再次收到编译器错误CS8766

这是一个重现问题的代码示例,并给出了如何修复它的提示。