Loại rỗng: cách tốt hơn để kiểm tra null hoặc 0 trong c #


85

Tôi đang làm việc trong một dự án mà tôi thấy rằng tôi đang kiểm tra những điều sau đây ở rất nhiều nơi:

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 trợ giúp 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?

Câu trả lời:


161

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 thức mở rộ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ó


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

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

11
@nailitdown: không hẳn, bạn chỉ cần một phương thức mở rộng cho Nullable <T>. gấp đôi? là một bí danh cho Nullable <double>. Chữ ký của bạn sẽ giống như sau: public static bool IsNullOrValue <T> (điều này Nullable <T>, t valueToCheck) nơi T: struct
Joshua Shannon

3
@nailitdown: (phần II) Câu lệnh return của bạn khi đó sẽ giống như return (value ?? default (T)). Equals (valueToCheck);
Joshua Shannon

2
Nếu bạn rút ngắn nó thành "IsNullOr (0)", nó sẽ tự nhiên được đọc là "là null hoặc 0"
ChrisFox 19/02/16

41

Sử dụng thuốc chung:

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à kiểu tham chiếu , valuesẽ được so sánh với null( default(T)), ngược lại, nếu Tlà a value type, giả sử là double, default(t)là 0d, đối với bool là false, đối với char là '\0', v.v.


1
phương thức mở rộng:public static bool IsNullOrValue<T>(this T? value, T valueToCheck) where T : struct { return (value ?? default(T)).Equals(valueToCheck); }
Behzad Ebrahimi

39

Mặc dù tôi khá thích câu trả lời được chấp nhận, nhưng tôi nghĩ rằng, để hoàn thiện, tùy chọn này cũng nên được đề cập:

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

Giải pháp này


¹ Tuy nhiên, điều này sẽ không ảnh hưởng đến quyết định của bạn vì những loại tối ưu hóa vi mô này không có khả năng tạo ra bất kỳ sự khác biệt nào.


19

Đây thực sự chỉ là một bản mở rộng của câu trả lời được chấp nhận của 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 ta không cần kiểm tra default (T) cho null vì chúng ta đang xử lý các kiểu giá trị hoặc cấu trúc! Điều này cũng có nghĩa là chúng ta có thể giả sử một cách an toàn T valueToCheck sẽ không rỗng; Nhớ đây 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 nhận được phương thức trong int ?, double ?, bool? Vân vân.

Ví dụ:

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

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

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

2

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

Nếu bạn đang xử lý các chuỗi, hãy sử dụng if (String.IsNullOrEmpty (myStr))


2

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

Chà, nếu bạn thực sự đang tìm kiếm một cách tốt hơn, bạn có thể thêm một lớp trừu tượng khác lên trên Rate. Đây là thứ tôi vừa nghĩ ra bằng cách sử dụng Nullable Design Pattern.

sử dụng Hệ thống;
sử dụng System.Collections.Generic;

không gian tên NullObjectPatternTest
{
    Chương trình lớp công cộng
    {
        public static void Main (string [] args)
        {
            var items = new List
                            {
                                Mục mới (RateFactory.Create (20)),
                                Mục mới (RateFactory.Create (null))
                            }

            PrintPricesForItems (mục);
        }

        private static void PrintPricesForItems (IEnumerable items)
        {
            foreach (var item trong các item)
                Console.WriteLine ("Giá mặt hàng: {0: C}", item.GetPrice ());
        }
    }

    public abstract class ItemBase
    {
        công khai Tóm tắt Tỷ lệ Tỷ lệ {get; }
        public int GetPrice ()
        {
            // KHÔNG cần kiểm tra xem Rate == 0 hay Rate == null
            trả về 1 * Rate.Value;
        }
    }

    hạng mục công khai: ItemBase
    {
        private readonly Rate _Rate;
        ghi đè công khai Tỷ lệ Tỷ lệ {get {return _Rate; }}
        public Item (Tỷ lệ giá) {_Rate = tỷ lệ; }
    }

    lớp niêm phong công khai RateFactory
    {
        public static Rate Create (int? rateValue)
        {
            if (! rateValue || rateValue == 0) 
                trả về mới NullRate ();
            trả về Tỷ lệ mới (rateValue);
        }
    }

    Hạng công khai
    {
        public int Giá trị {get; bộ; }
        public virtual bool HasValue {get {return (Giá trị> 0); }}
        public Rate (int value) {Giá trị = giá trị; }
    }

    lớp công khai NullRate: Tỷ lệ
    {
        public override bool HasValue {get {return false; }}
        public NullRate (): base (0) {}
    }
}

1
tôi nghĩ rằng bạn nói đúng đó loại bỏ các giá trị null ở một số giai đoạn trước đó sẽ đã con đường để đi
nailitdown

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

2

Mẫu mã của bạn sẽ không thành công. Nếu obj là null thì obj.ToString () sẽ dẫn đến ngoại lệ tham chiếu null. Tôi đã cắt ngắn quy trình và kiểm tra phản đối rỗng khi 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 mà bạn đang kiểm tra là null hay zero? Trên String có một hàm IsNullOrEmpty tuyệt vời, với tôi đây sẽ là một cách sử dụng tuyệt vời của các phương thức mở rộng để triển khai một phương thức IsNullOrZero trên int? kiểu.

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


cổ vũ cho việc đánh bắt lỗi - trong dự án này tôi cần phải kiểm tra chống int ?, gấp đôi ?, thập phân ?, vv mà là lý do tại sao tôi đang sử dụng "đối tượng"
nailitdown

Nhớ cái gì đó '?' chỉ là đường biên dịch cho kiểu INullable <T>, vì vậy bạn có thể lấy INullable <T> làm parm và sau đó jsut so sánh nó với null (parm == null) và nếu không null thì so sánh với 0.
Walden Leverich

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

1
Phản xạ chậm , hãy cẩn thận với những giải pháp như thế này. Tôi không phản đối sự phản chiếu, nhưng tôi sẽ 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.
Walden Leverich

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

Trên thực tế, không. Activator.CreateInstance (obj.GetType ()) sẽ trả về null cho các kiểu null, tôi tin.
cấu hình

@configurator: khi các kiểu nullable được đóng hộp, chúng được đóng hộp dưới dạng cấu trúc cơ bản, tức là, điều này sẽ không tạo ra một giá trị nullable, mà là một cấu trúc không nullable có giá trị mặc định.
Eamon Nerbonne

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

giải pháp của bạn làm việc cho một thuộc tính, tôi nên đã chỉ định tôi có nhiều tài sản của mặt hàng tương tự để kiểm tra null / zero
nailitdown

0

Đừng quên, đối với chuỗi, bạn luôn có thể 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.
dance2die

-1

Một bước nữa từ câu trả lời hay của Joshua Shannon . Bây giờ với việc ngăn chặn quyền anh / 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));
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.