可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm working on a project where i find i'm checking for the following in many, many places:
if(item.Rate == 0 || item.Rate == null) { }
more as a curiousity than anything, what's the best way to check for both cases?
I've added a helper method which is:
public static bool nz(object obj)
{
var parsedInt = 0;
var parsed = int.TryParse(obj.ToString(), out parsedInt);
return IsNull(obj) || (parsed && parsedInt == 0);
}
Is there a better way?
回答1:
I like if ((item.Rate ?? 0) == 0) { }
Update 1:
You could also define an extension method like:
public static bool IsNullOrValue(this double? value, double valueToCheck)
{
return (value??valueToCheck) == valueToCheck;
}
And use it like this:
if(item.IsNullOrValue(0)){}
// but you don't get much from it
回答2:
Using generics:
static bool IsNullOrDefault<T>(T value)
{
return object.Equals(value, default(T));
}
//...
double d = 0;
IsNullOrDefault(d); // true
MyClass c = null;
IsNullOrDefault(c); // true
If T
it's a reference type, value
will be compared with null
( default(T)
), otherwise, if T
is a value type
, let's say double, default(t)
is 0d, for bool is false
, for char is '\0'
and so on...
回答3:
Although I quite like the accepted answer, I think that, for completeness, this option should be mentioned as well:
if (item.Rate.GetValueOrDefault() == 0) { }
This solution
- does not require an additional method,
- is faster than all the other options, since GetValueOrDefault is a single field read operation¹ and
- reads easier than
((item.Rate ?? 0) == 0)
(this might be a matter of taste, though).
¹ This should not influence your decision, though, since these kinds of micro-optimization are unlikely to make any difference.
回答4:
This is really just an expansion of Freddy Rios' accepted answer only using Generics.
public static bool IsNullOrDefault<T>(this Nullable<T> value) where T : struct
{
return default(T).Equals( value.GetValueOrDefault() );
}
public static bool IsValue<T>(this Nullable<T> value, T valueToCheck) where T : struct
{
return valueToCheck.Equals((value ?? valueToCheck));
}
NOTE we don't need to check default(T) for null since we are dealing with either value types or structs! This also means we can safely assume T valueToCheck will not be null; Remember here that T? is shorthand Nullable<T> so by adding the extension to Nullable<T> we get the method in int?, double?, bool? etc.
Examples:
double? x = null;
x.IsNullOrDefault(); //true
int? y = 3;
y.IsNullOrDefault(); //false
bool? z = false;
z.IsNullOrDefault(); //true
回答5:
I agree with using the ?? operator.
If you're dealing with strings use if(String.IsNullOrEmpty(myStr))
回答6:
is there a better way?
Well, if you are really looking for a better way, you can probably add another layer of abstraction on top of Rate.
Well here is something I just came up with using Nullable Design Pattern.
using System;
using System.Collections.Generic;
namespace NullObjectPatternTest
{
public class Program
{
public static void Main(string[] args)
{
var items = new List
{
new Item(RateFactory.Create(20)),
new Item(RateFactory.Create(null))
};
PrintPricesForItems(items);
}
private static void PrintPricesForItems(IEnumerable items)
{
foreach (var item in items)
Console.WriteLine("Item Price: {0:C}", item.GetPrice());
}
}
public abstract class ItemBase
{
public abstract Rate Rate { get; }
public int GetPrice()
{
// There is NO need to check if Rate == 0 or Rate == null
return 1 * Rate.Value;
}
}
public class Item : ItemBase
{
private readonly Rate _Rate;
public override Rate Rate { get { return _Rate; } }
public Item(Rate rate) { _Rate = rate; }
}
public sealed class RateFactory
{
public static Rate Create(int? rateValue)
{
if (!rateValue || rateValue == 0)
return new NullRate();
return new Rate(rateValue);
}
}
public class Rate
{
public int Value { get; set; }
public virtual bool HasValue { get { return (Value > 0); } }
public Rate(int value) { Value = value; }
}
public class NullRate : Rate
{
public override bool HasValue { get { return false; } }
public NullRate() : base(0) { }
}
}
回答7:
You code sample will fail. If obj is null then the obj.ToString() will result in a null reference exception. I'd short cut the process and check for a null obj at the start of your helper function. As to your actual question, what's the type you're checking for null or zero? On String there's a great IsNullOrEmpty function, seems to me this would be a great use of extension methods to implement an IsNullOrZero method on the int? type.
Edit: Remember, the '?' is just compiler sugar for the INullable type, so you could probably take an INullable as the parm and then jsut compare it to null (parm == null) and if not null compare to zero.
回答8:
public static bool nz(object obj)
{
return obj == null || obj.Equals(Activator.CreateInstance(obj.GetType()));
}
回答9:
class Item{
bool IsNullOrZero{ get{return ((this.Rate ?? 0) == 0);}}
}
回答10:
Don't forget, for strings, you can always use:
String.IsNullOrEmpty(str)
Instead of:
str==null || str==""
回答11:
One step further from Joshua Shannon's nice answer. Now with preventing boxing/unboxing:
public static class NullableEx
{
public static bool IsNullOrDefault<T>(this T? value)
where T : struct
{
return EqualityComparer<T>.Default.Equals(value.GetValueOrDefault(), default(T));
}
}