对于“可能将值类型与'null'进行比较”我该怎么办?


71

在为自定义NUnit约束编写此方法时。

    private void AddMatchFailure<TExpected, TActual>(string failureName, TExpected expected, TActual actual)
    {
        _matchFailures.Add(
            String.Format(MatchFailureFormat, failureName,
            (expected == null) ? "null" : expected.ToString(),
            (actual == null) ? "null" : actual.ToString()));
    }

Resharper警告expectedactual可能是ValueType对象。

例如TExpected是DateTime
   预期== null; //但是DateTime是一个结构。

将ValueType与null进行比较时的规则是什么?如何在不通过添加类约束来限制通用参数的情况下编写该方法来解决该问题?

Answers:


81

不要更改代码-只需忽略警告即可。如果type参数是非空值类型,则比较将始终失败,并且将始终调用它ToString()。我不知道它是否真的被淘汰了,但是我不会感到惊讶……而且这听起来也不像是对性能至关重要的代码:)

我个人将警告设置为“开”,但是在这种特殊情况下可以忽略它-可能会添加评论。

我想我在重新实现LINQ to Objects时也遇到了同样的警告。


63
我添加了“ //我已让Skeets先生表示允许忽略此警告。” 似乎可以解决问题:)
Grokodile 2011年

19
@panamack:我可以在“ Skeet's”中请求撇号吗?助教。
乔恩·斯基特

65
当然,“ //我已经让Skeet先生(在这里TODO添加撇号)明确表示可以忽略此警告。”
Grokodile 2011年

15
值得注意的是,如果有人真的被错误消息困扰,他们总是可以这样做Object.ReferenceEquals(objA, null),实际上只是objA == objB在.NET源代码中进行调用。而且,我非常确定这将以某种方式被JITted或内联。令人高兴的是,错误消息虽然消失了,但呼叫仍然有效:)
myermian

4
为了完整起见,Eric Lippert表示,在为非空值类型的类型参数编译方法时,JIT实际上确实将“ val == null”检查替换为“ false”。
Joe Amenta

6

将ValueType与null进行比较时的规则是什么?如何在不通过添加类约束来限制通用参数的情况下编写该方法来解决该问题?

如果您不知道它们将是引用类型,那么您可以说

private void AddMatchFailure<TExpected, TActual>(
    string failureName,
    TExpected expected,
    TActual actual
) {
    _matchFailures.Add(
        String.Format(MatchFailureFormat, failureName,
        IsDefault<TExpected>(expected) ? DefaultStringForType<TExpected>() : expected.ToString(),
        IsDefault<TActual>(actual) ? DefaultStringForType<TActual>() : actual.ToString()
    );
}

private bool IsDefault<T>(T value) {
    if(typeof(T).IsValueType) {
        return default(T).Equals(value);
    }
    else {
        return Object.Equals(null, value);
    }
}

private string DefaultStringForType<T>() {
    if(typeof(T).IsValueType) {
        return default(T).ToString();
    }
    else {
        return "null";
    }
}

但我认为他想与之进行比较null
CodesInChaos 2011年

@CodeInChaos:default引用类型为null
杰森

1
@Jason,但不是null非空值类型。对于比较而言,false对于没有的类型,简单地使其成为常量是有意义的null。这可能是OP代码的理想行为。
CodesInChaos 2011年

@CodeInChaos:default(Nullable<T>)whereT是非空值类型是Nullable<T>where Nullable<T>.HasValueis false(即is null)的实例。
杰森

1
@Jason我知道,这与我对您的代码的反对无关。你DefaultStringForType不处理Nullable<T>null正确。而且除此之外,OP的代码还比您的代码干净得多。
CodesInChaos 2011年

2

我正在使用类似这样的方法来检查泛型类型的null:

if (Equals(result, Default(T)))

9
小心!default(int)为0,可以是有效且显式设置的值。检查default(T)与检查null完全不同。
ANeves认为SE是邪恶的,2013年

1
+1 @ ANeves,resharper在那里的帮助页面中建议这个,对我来说,它的代码闻起来有confluence.jetbrains.com/display/ReSharper/…–
Choco Smith

我也讨厌那个例子,因为很明显这是大多数人都想0.ToString()称呼他的情况……
NobodysNightmare 2014年

-3
private void AddMatchFailure<TExpected, TActual>(string failureName, TExpected expected, TActual actual)
{
    _matchFailures.Add(
        String.Format(MatchFailureFormat, failureName,
        (expected == default(TExpected)) ? "null" : expected.ToString(),
        (actual == default(TActual)) ? "null" : actual.ToString()));
}

应该做。

default(T)给出该类型的默认值,对于null的引用类型-依赖于其他类型。((enumType)0例如,它等于)。


2
然后,如果要比较整数,它将显示“ null”而不是0。使测试失败难以理解的方法;)
Jon Skeet

这给了我一个编译器警告“无法将运算符==应用于类型'TExpected'和'TExpected'的操作数”
Grokodile 2011年

@Jon这是正确的,但这是摆脱适合参数的警告的唯一方法。:p
Massif

2
问题不问如何消除警告。它询问该怎么做:)
乔恩·斯凯特

@Jon-足够公平了……(现在,“亲切让步”的图释在哪里)
Massif
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.