Nullable types: better way to check for null or zero in c#

后端 未结 11 739
孤街浪徒
孤街浪徒 2020-11-30 22:45

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) { }

mo

相关标签:
11条回答
  • 2020-11-30 23:18
    public static bool nz(object obj)
    {
        return obj == null || obj.Equals(Activator.CreateInstance(obj.GetType()));
    }
    
    0 讨论(0)
  • 2020-11-30 23:19

    Don't forget, for strings, you can always use:

    String.IsNullOrEmpty(str)
    

    Instead of:

    str==null || str==""
    
    0 讨论(0)
  • 2020-11-30 23:21

    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.

    0 讨论(0)
  • 2020-11-30 23:22

    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) { }
        }
    }
    
    0 讨论(0)
  • 2020-11-30 23:23

    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));
        }
    }
    
    0 讨论(0)
  • 2020-11-30 23:25

    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
    
    0 讨论(0)
提交回复
热议问题