我编写了以下扩展方法:
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
时收到编译器警告错误:
“字符串”类型?不能在通用类型或方法'INotifyPropertyChangedExtensions.NotifyChanged(INotifyPropertyChanged,ref T,T,Action,string?)'中用作类型参数'T'。类型参数“字符串”的可空性与约束类型“ System.IEquatable”不匹配。
AFAICT错误是说string?
不能强制转换为IEquatable<string?>
,只能将string
强制强制转换为IEquatable<string>
。
我该如何解决?应用一些属性?还是其他?
答案 0 :(得分:4)
您的问题是:
where T : IEquatable<T>
这表示T
必须是不可为空的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
为null
,这也解决了您的NRE问题:
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
调用。 / p>
如果您确实希望通过筹款活动来参加比赛,则只需传递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);