C# 中的类特定函数略微修改为 UWP 模板可观察



我正在使用最新的UWP(和Windows Template Studio(方法构建一个应用程序。有一个聪明的类叫做"可观察"。 所以,这只是背景。我想修改第 13 行上的条件,以便双精度的可忽略不计的更改不会标记属性更改。因此,我扩充了第 13 行并创建了一个名为 Ignore Change...

protected void Set<T>(ref T storage, T value, [CallerMemberName]string propertyName = null)
{
if ((typeof(T) == typeof(double) && NegligibleChange(storage, value)) || Equals(storage, value))
{
return;
}
storage = value;
OnPropertyChanged(propertyName);
}
private bool NegligibleChange(double  x, double y)
{
return Math.Abs(x - y) <= 1e-10;
}
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

这是行不通的,因为它说"无法将 T 转换为双精度"。有没有办法解决这个问题?

提问者发布的答案通常被认为是正确的方法。 当您有一个泛型方法必须对一种特定类型执行某些特殊操作时,它就不再是泛型方法。

也就是说,首先,实际问题从未得到解答,其次,需要考虑这种方法的一些注意事项。

这是行不通的,因为它说"无法将 T 转换为双精度"。有没有办法解决这个问题?

是的,有几种方法可以做到这一点,其中一些比其他方法更好。

首先,这通常是一种糟糕的型式测试方式。

typeof(T) == typeof(double)

你手头有两个 T,所以你会这样做:

protected void Set<T>(ref T storage, T value, blah blah blah)
{
if (Equals(storage, value))
return;
double? oldValue = storage as double?;
double? newValue = value as double?;
if (oldValue != null && newValue != null && Negligible(oldValue.Value, newValue.Value))
return;
...

请注意,一个不好的方法是:

protected void Set<T>(ref T storage, T value, blah blah blah)
{
if (Equals(storage, value))
return;
if (storage is double && value is double) 
{
double oldValue = (double)(object)storage;
double newValue = (double)(object)value;
if (Negligible(...

因为这会受到拳击惩罚;抖动不一定足够聪明,无法优化双步>对象>双步,这是昂贵的。


虽然正如我所说,一般来说,如果可能的话,专业化是个好主意,请考虑以下情况。 如果您专门制作一个可以执行双精度的版本和一个执行其他所有操作的版本,那么:

Set(ref someDouble, 1.23)

将调用双重版本,但是

Set<double>(ref someDouble, 1.23)

仍将调用通用版本。 C# 更喜欢非泛型版本而不是泛型版本,但如果显式请求泛型版本,则会得到它。

同样,如果从通用上下文调用您:

class C<T> 
{
T storage;
void Frob(Blah blah, T value) {
blah.Set<T>(ref storage, value);
}

然后C<double>不会调用您的特殊版本;同样,这会根据请求调用Set<double>

所以要小心。

好吧,我自己的问题有一个答案。泛型很难理解,你知道的。如果以下不是处理此问题的方法,请发表评论。需要的是添加具有双精度输入签名的 Set 函数的非泛型版本。这样,在运行时就没有其他条件。

protected void Set<T>(ref T storage, T value, [CallerMemberName]string propertyName = null)
{
if (Equals(storage, value))
{
return;
}
storage = value;
OnPropertyChanged(propertyName);
}
protected void Set(ref double storage, double value, [CallerMemberName]string propertyName = null)
{
if (NegligibleChange(storage, value))
{
return;
}
storage = value;
OnPropertyChanged(propertyName);
}
private bool NegligibleChange(double  x, double y)
{
return Math.Abs(x - y) <= 1e-10;
}
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

相关内容

  • 没有找到相关文章

最新更新