2009-03-11 27 views
64

tôi đang làm việc trên một dự án mà tôi tìm thấy tôi đang kiểm tra sau trong nhiều, nhiều nơi:loại Nullable: Cách tốt nhất để kiểm tra null hoặc không có trong C#

hơn
if(item.Rate == 0 || item.Rate == null) { } 

như một sự tò mò hơn bất cứ điều gì, cách tốt nhất để kiểm tra cả hai trường hợp là gì?

Tôi đã thêm một phương pháp helper đó là:

public static bool nz(object obj) 
{ 
    var parsedInt = 0; 
    var parsed = int.TryParse(obj.ToString(), out parsedInt); 
    return IsNull(obj) || (parsed && parsedInt == 0); 
} 

Có cách nào tốt hơn?

Trả lời

122

Tôi thích if ((item.Rate ?? 0) == 0) { }

Cập nhật 1:

Bạn cũng có thể xác định một phương pháp khuyến nông như:

public static bool IsNullOrValue(this double? value, double valueToCheck) 
{ 
    return (value??valueToCheck) == valueToCheck; 
} 

Và sử dụng nó như thế này:

if(item.IsNullOrValue(0)){} // nhưng bạn không nhận được nhiều từ nó

+1

Điều làm đẹp. – Patrick

+3

cảm ơn bạn - rất ngắn gọn! tôi đã quan tâm đến khả năng đọc, nhưng đi đến kết luận rằng nó sẽ là hoàn toàn có thể đọc được tôi thực sự hiểu được ?? nhà điều hành. – nailitdown

+2

Bạn nên sử dụng phương pháp mở rộng; trong khi nó có thể đọc được tại thời điểm viết, mã nhỏ này đòi hỏi một phần tư tưởng, có nghĩa là nếu bạn cố gắng đọc mã và nó sử dụng nó - bạn bị phân tâm khỏi vấn đề chính của bạn. – configurator

0
public static bool nz(object obj) 
{ 
    return obj == null || obj.Equals(Activator.CreateInstance(obj.GetType())); 
} 
+1

Phản ánh là * chậm *, hãy cẩn thận với các giải pháp như thế này.Tôi không phản đối sự phản chiếu, nhưng tôi không mong đợi nó trong một chức năng "đơn giản" như thế này và nó sẽ khiến tôi mất cảnh giác. –

+0

thực hiện điều này có thực sự kiểm tra không? – nailitdown

+0

Thực ra, không. Activator.CreateInstance (obj.GetType()) sẽ trả về null cho các kiểu nullable, tôi tin. – configurator

2

Tôi đồng ý với việc sử dụng ?? nhà điều hành.

Nếu bạn đang làm việc với chuỗi sử dụng if (string.IsNullOrEmpty (mystr))

2

Bạn mẫu mã sẽ thất bại. Nếu obj là null thì obj.ToString() sẽ dẫn đến một ngoại lệ tham chiếu null. Tôi muốn cắt ngắn quá trình và kiểm tra một obj null lúc bắt đầu chức năng trợ giúp của bạn. Đối với câu hỏi thực tế của bạn, loại bạn đang kiểm tra là null hoặc 0 là gì? Trên String có một hàm IsNullOrEmpty tuyệt vời, dường như với tôi điều này sẽ là một sử dụng tuyệt vời của các phương pháp mở rộng để thực hiện một phương pháp IsNullOrZero trên int? kiểu.

Chỉnh sửa: Hãy nhớ rằng, '?' chỉ là trình biên dịch đường cho loại Inullable, vì vậy bạn có thể có thể mất một INullable như parm và sau đó jsut so sánh nó với null (parm == null) và nếu không null so sánh với số không.

+0

cổ vũ để bắt lỗi đó - trong dự án này tôi cần kiểm tra đối với int ?, double ?, decimal ?, v.v. đó là lý do tại sao tôi đang sử dụng "đối tượng" – nailitdown

+0

Hãy nhớ rằng, '?' chỉ là đường biên dịch cho loại INullable , vì vậy bạn có thể có thể mất một INullable như parm và sau đó jsut so sánh nó với null (parm == null) và nếu không null so với 0. –

0
class Item{ 
bool IsNullOrZero{ get{return ((this.Rate ?? 0) == 0);}} 
} 
+0

giải pháp của bạn hoạt động cho một thuộc tính, tôi nên đã chỉ định tôi có nhiều thuộc tính của cùng một mục để kiểm tra null/zero – nailitdown

35

Sử dụng 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 

Nếu T đó là một loại tham khảo, value sẽ được so sánh với null (default(T)), nếu không, nếu T là một value type, chúng ta hãy nói đôi, default(t) là 0d, đối với bool là false, đối với char là '\0' và cứ thế ...

1

có cách nào tốt hơn không?

Vâng, nếu bạn đang thực sự tìm kiếm một cách tốt hơn, bạn có thể có thể thêm một lớp trừu tượng khác ở trên cùng của Tỷ lệ. Đây là một cái gì đó tôi chỉ đưa ra bằng cách sử dụng 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) { } 
    } 
} 
+1

tôi nghĩ rằng bạn đúng là loại bỏ giá trị null ở giai đoạn trước đó sẽ là cách để đi – nailitdown

+0

Không chính xác. Có một khái niệm gọi là "Tái cấu trúc". Bạn có thể cấu trúc lại mã của bạn theo hướng mẫu tốt hơn hoặc cấu trúc tốt hơn. Bạn luôn có thể * loại bỏ * giá trị nullable ở các giai đoạn sau. – Sung

0

Đừng quên, cho các chuỗi, bạn có thể luôn luôn sử dụng:

String.IsNullOrEmpty(str) 

Thay vì:

str==null || str=="" 
+1

Câu hỏi so sánh với "0" không phải là một chuỗi rỗng. – Sung

16

Đây thực sự chỉ là một sự mở rộng của câu trả lời chấp nhận Freddy Rios' chỉ sử dụng 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)); 
} 

LƯU Ý chúng tôi không cần phải kiểm tra mặc định (T) for null vì chúng ta đang đối phó với một trong hai loại giá trị hoặc cấu trúc! Điều này cũng có nghĩa là chúng ta có thể giả định T valueToCheck một cách an toàn sẽ không được null; Hãy nhớ rằng T? là viết tắt Nullable <T> vì vậy bằng cách thêm phần mở rộng vào Nullable <T> chúng ta có phương thức trong int ?, double ?, bool? vv

Ví dụ:

double? x = null; 
x.IsNullOrDefault(); //true 

int? y = 3; 
y.IsNullOrDefault(); //false 

bool? z = false; 
z.IsNullOrDefault(); //true 
21

Mặc dù tôi rất thích câu trả lời được chấp nhận, tôi nghĩ rằng, cho đầy đủ, tùy chọn này nên được đề cập đến như:

if (item.Rate.GetValueOrDefault() == 0) { } 

Giải pháp này

  • không yêu cầu phương thức bổ sung,
  • nhanh hơn tất cả các tùy chọn khác, vì GetValueOrDefault is a single field read operation ¹ và
  • đọc dễ dàng hơn ((item.Rate ?? 0) == 0) (điều này có thể là vấn đề về hương vị).

¹ này không nên ảnh hưởng đến quyết định của bạn, tuy nhiên, kể từ khi các loại vi-tối ưu hóa không có khả năng thực hiện bất kỳ sự khác biệt.

Các vấn đề liên quan