c# - 参数的可空性与约束类型不匹配

标签 c# nullable-reference-types

我写了下面的扩展方法:

public static void NotifyChanged<T>(this INotifyPropertyChanged inpc, ref T current, T newValue, Action<PropertyChangedEventArgs> eventRaiser, [CallerMemberName] string? name = null) where T : IEquatable<T> {
    if (current.Equals(newValue)) { return; }
    current = newValue;
    eventRaiser(new PropertyChangedEventArgs(name));
}

可以这样使用:

public class Foo : Bar, INotifyPropertyChanged {
    public event PropertyChangedEventHandler? PropertyChanged;

    private string? rootExpression;

    public string? RootExpression {
        get => rootExpression;
        set => this.NotifyChanged(ref rootExpression, value, args => PropertyChanged?.Invoke(this, args));
    }
}

这节省了大量编写 INPC 感知属性的样板文件。

但是,我现在在调用 NotifyChanged 时收到编译器警告错误:

The type 'string?' cannot be used as type parameter 'T' in the generic type or method 'INotifyPropertyChangedExtensions.NotifyChanged(INotifyPropertyChanged, ref T, T, Action, string?)'. Nullability of type argument 'string?' doesn't match constraint type 'System.IEquatable'.

AFAICT 错误是说 string?无法转换为 IEquatable<string?> , 只有 string可以转换为 IEquatable<string> .

我该如何解决这个问题?应用一些属性?还是别的?

最佳答案

你的问题是:

where T : IEquatable<T>

这表示 T必须是不可为 null 的 IEquatable<T> .您希望它可以为空。你可以通过添加 ? 来表达这一点:

where T : IEquatable<T>?

请注意,这将在 if (current.Equals(newValue)) 上提示, 如果 current 将会抛出是null .


执行此操作的正常方法不是通过约束 T成为IEquatable<T> , 但要使用 EqualityComparer<T>.Default .如果T工具 IEquatable<T> ,这为您提供了一个调用 IEquatable<T>.Equals 的相等比较器,否则它会回退到调用正常的 object.Equals .

如果current,这也解决了您的 NRE 问题是null :

public static void NotifyChanged<T>(
    this INotifyPropertyChanged inpc,
    ref T current, T newValue,
    Action<PropertyChangedEventArgs> eventRaiser,
    [CallerMemberName] string? name = null)
{
    if (EqualityComparer<T>.Default.Equals(current, newValue)) { return; }
    current = newValue;
    eventRaiser(new PropertyChangedEventArgs(name));
}

也难得传入eventRaiser : 通常你会做 NotifyChanged实现 INotifyPropertyChanged 的基类上的方法,而不是将其作为扩展方法。然后你可以让NotifyChanged提高PropertyChanged事件本身,或者您编写另一个方法,例如 OnPropertyChanged这引发了PropertyChanged并从 NotifyChanged 调用它.

如果你确实想传递要引发的事件,你可以传递 PropertyChangedEventHandler :

public static void NotifyChanged<T>(
    this INotifyPropertyChanged _,
    ref T current, T newValue,
    PropertyChangedEventHandler eventHandler,
    [CallerMemberName] string? name = null)
{
    if (EqualityComparer<T>.Default.Equals(current, newValue)) { return; }
    current = newValue;
    eventHandler?.Invoke(this, new PropertyChangedEventArgs(name));
}

this.NotifyChanged(ref rootExpression, value, PropertyChanged);

关于c# - 参数的可空性与约束类型不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60668629/

相关文章:

c# - IEquatable<T> 和 [AllowNull]

c# - 可空字符串 (string?) 和初始化为可原谅空值的字符串 (字符串 s = null!) 之间有什么区别

c# - 在 F# 中使用可为空的引用类型

c# - 获取 GeometryModel3D 的名称

c# - Function C++ 到 C#(安全代码)

c# - 尝试从服务器删除图像

c# - 可为 null 的引用类型的注释只能在 '#nullable' 上下文中的代码中使用

c# - 取回匿名类型

c# - 通用嵌套类型 : cannot convert from X<T> to X<T>

c# - 如何将 NonNullable 引用属性标记为安全?