Die zweite Methode ist um ein Vielfaches effektiver (vor allem wegen des Inlinings und Boxings des Compilers, aber die Zahlen sind trotzdem sehr aussagekräftig):
public static bool CheckObjectImpl(object o)
{
return o != null;
}
public static bool CheckNullableImpl<T>(T? o) where T: struct
{
return o.HasValue;
}
Benchmark-Test:
BenchmarkDotNet=v0.10.5, OS=Windows 10.0.14393
Processor=Intel Core i5-2500K CPU 3.30GHz (Sandy Bridge), ProcessorCount=4
Frequency=3233539 Hz, Resolution=309.2587 ns, Timer=TSC
[Host] : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1648.0
Clr : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1648.0
Core : .NET Core 4.6.25009.03, 64bit RyuJIT
Method | Job | Runtime | Mean | Error | StdDev | Min | Max | Median | Rank | Gen 0 | Allocated |
-------------- |----- |-------- |-----------:|----------:|----------:|-----------:|-----------:|-----------:|-----:|-------:|----------:|
CheckObject | Clr | Clr | 80.6416 ns | 1.1983 ns | 1.0622 ns | 79.5528 ns | 83.0417 ns | 80.1797 ns | 3 | 0.0060 | 24 B |
CheckNullable | Clr | Clr | 0.0029 ns | 0.0088 ns | 0.0082 ns | 0.0000 ns | 0.0315 ns | 0.0000 ns | 1 | - | 0 B |
CheckObject | Core | Core | 77.2614 ns | 0.5703 ns | 0.4763 ns | 76.4205 ns | 77.9400 ns | 77.3586 ns | 2 | 0.0060 | 24 B |
CheckNullable | Core | Core | 0.0007 ns | 0.0021 ns | 0.0016 ns | 0.0000 ns | 0.0054 ns | 0.0000 ns | 1 | - | 0 B |
Benchmark-Code:
public class BenchmarkNullableCheck
{
static int? x = (new Random()).Next();
public static bool CheckObjectImpl(object o)
{
return o != null;
}
public static bool CheckNullableImpl<T>(T? o) where T: struct
{
return o.HasValue;
}
[Benchmark]
public bool CheckObject()
{
return CheckObjectImpl(x);
}
[Benchmark]
public bool CheckNullable()
{
return CheckNullableImpl(x);
}
}
https://github.com/dotnet/BenchmarkDotNet verwendet wurde
Wenn Sie also die Möglichkeit haben (z.B. durch das Schreiben von benutzerdefinierten Serialisierern), Nullable in einer anderen Pipeline zu verarbeiten als object
- und ihre spezifischen Eigenschaften verwenden - tun Sie es und verwenden Sie Nullable spezifische Eigenschaften. Also von konsistentem Denken Standpunkt aus gesehen HasValue
sollte bevorzugt werden. Konsequentes Denken kann Ihnen helfen, besseren Code zu schreiben und nicht zu viel Zeit in Details zu investieren.
PS . Die Leute sagen, dass die Beratung "lieber HasValue wegen der konsequenten Denken" ist nicht verwandt und nutzlos. Können Sie die Leistung dieses Systems vorhersagen?
public static bool CheckNullableGenericImpl<T>(T? t) where T: struct
{
return t != null; // or t.HasValue?
}
PPS Die Leute machen weiter Minus, anscheinend versucht niemand, die Leistung von CheckNullableGenericImpl
. Ich werde Ihnen sagen: es Compiler wird nicht helfen Sie ersetzen !=null
con HasValue
. HasValue
sollte direkt verwendet werden, wenn Sie an der Leistung interessiert sind.
10 Stimmen
Ich habe eine ähnliche Frage gestellt... und einige gute Antworten erhalten: stackoverflow.com/questions/633286/
3 Stimmen
Persönlich würde ich verwenden
HasValue
da ich der Meinung bin, dass Wörter besser lesbar sind als Symbole. Es liegt aber ganz an Ihnen und daran, was zu Ihrem Stil passt.1 Stimmen
.HasValue
macht mehr Sinn, da es bedeutet, dass der Typ vom TypT?
statt eines Typs, der nullbar sein kann, wie z. B. Strings.