Kiểm tra nếu một đối tượng là null trong C #


226

Tôi muốn ngăn chặn xử lý thêm trên một đối tượng nếu nó là null.

Trong đoạn mã sau tôi kiểm tra xem đối tượng có null không:

if (!data.Equals(null))

if (data != null)

Tuy nhiên, tôi nhận được NullReferenceExceptiontại dataList.Add(data). Nếu đối tượng là null, nó thậm chí không bao giờ được đưa vào if-statement!

Vì vậy, tôi hỏi liệu đây có phải là cách kiểm tra thích hợp nếu một đối tượng là null:

public List<Object> dataList;
public  bool AddData(ref Object data)
    bool success = false;
    try
    {
        // I've also used "if (data != null)" which hasn't worked either
        if (!data.Equals(null))
        {
           //NullReferenceException occurs here ...
           dataList.Add(data);
           success = doOtherStuff(data);
        }
    }
    catch (Exception e)
    {
        throw new Exception(e.ToString());
    }
    return success;
}

Nếu đây là cách kiểm tra thích hợp nếu đối tượng là null, tôi đang làm gì sai (làm cách nào tôi có thể ngăn chặn việc xử lý thêm trên đối tượng để tránh NullReferenceException)?


13
Bạn cũng nên sử dụng throw e;so vớithrow new Exception(e.ToString());
Nix

17
trong C # bạn nên luôn luôn sử dụng != nulltrong kiểm tra null của bạn. .Equalssẽ luôn ném một ngoại lệ nếu đối tượng là null.
Kyle Trauberman

42
@Nix: throw e;không tốt hơn nhiều. throw;, mặt khác ...
Jon

4
@developer: e.ToString()sẽ tạo ra một chuỗi bao gồm không chỉ thông báo lỗi, mà cả chuỗi của tất cả InnerExceptionsvà dấu vết ngăn xếp. Vì vậy, đó là một thông điệp ngoại lệ rất nặng. Nếu bạn (đúng!) Muốn lưu giữ thông tin này và giữ nơi nó thuộc về, hãy sử dụng một cách đơn giản throw;.
Jon

14
Việc thử / bắt không làm gì vào lúc này. Mọi người đều nói chỉ sử dụng "ném" nhưng nếu bạn không làm gì với ngoại lệ mà lại ném nó, tại sao lại có một khối thử / bắt? Thông thường, bạn nắm bắt các ngoại lệ để xử lý chúng một cách duyên dáng, dọn sạch các tài nguyên (tốt hơn với mệnh đề "cuối cùng") hoặc thực hiện một số loại đăng nhập trước khi ném lại ngoại lệ. Không có điều nào trong số này xảy ra trong mã này, vì vậy không cần thử / bắt cả.
David Peterson

Câu trả lời:


252

Đó không phải datanull, nhưng dataList.

Bạn cần tạo một cái với

public List<Object> dataList = new List<Object>();

Thậm chí tốt hơn: vì đó là một lĩnh vực, làm cho nó private. Và nếu không có gì ngăn cản bạn, hãy làm cho nó cũng readonly. Chỉ cần thực hành tốt.

Qua một bên

Cách chính xác để kiểm tra vô hiệu là if(data != null). Loại kiểm tra này có mặt khắp nơi cho các loại tham chiếu; thậm chí Nullable<T>ghi đè toán tử đẳng thức là cách thể hiện thuận tiện hơn nullable.HasValuekhi kiểm tra tính vô hiệu.

Nếu bạn làm if(!data.Equals(null))thì bạn sẽ nhận được NullReferenceExceptionnếu data == null. Đó là loại hài hước kể từ khi tránh ngoại lệ này là mục tiêu ở nơi đầu tiên.

Bạn cũng đang làm điều này:

catch (Exception e)
{
    throw new Exception(e.ToString());
}

Điều này chắc chắn là không tốt. Tôi có thể tưởng tượng rằng bạn đặt nó ở đó chỉ để bạn có thể đột nhập vào trình gỡ lỗi trong khi vẫn ở trong phương thức, trong trường hợp này bỏ qua đoạn này. Mặt khác, không bắt ngoại lệ cho không có gì. Và nếu bạn làm, hãy thử lại chúng bằng cách sử dụng throw;.


5
Tôi cũng đã thấy Object.ReferenceEquals (obj, null) cho mục đích này. Có phải để tránh ghi đè bình đẳng?
Luca

2
@LucaPiccioni Tôi đã sử dụng nó để ngăn chặn khiếu nại kiểu giá trị khi sử dụng thuốc generic: geekality.net/2009/11/13/generics-and-checking-for-null
Svish

4
Tôi thích null != data. Đặt hằng số đầu tiên biến lỗi đánh máy đầu xương null = datathành lỗi trình biên dịch, thay vì gán không chủ ý. (Cũng hoạt động cho ==.)
jpmc26

6
@ jpmc26: Trong C # if (data = null)đã là lỗi thời gian biên dịch, vì vậy ngay cả khi phải mất hàng thập kỷ để đến đó, chúng tôi không thực sự cần phải đề phòng điều đó nữa. Ngay cả trình biên dịch C ++ cũng sẽ dễ dàng đưa ra cảnh báo về khả năng gán ngoài ý muốn cho mã đó.
Jon

Luca, bạn cũng có thể tránh ghi đè bằng bằng cách truyền tới 'đối tượng' trong thử nghiệm. Trên một tĩnh mạch tương tự, câu trả lời này sẽ yêu cầu điều này thay vào đó: "if ((object) data! = Null)" vì nó tránh được các lỗi khi đẳng thức đã bị ghi đè.
DAG

81

trong C #> 7.0 sử dụng

if (obj is null) ...

Điều này sẽ bỏ qua bất kỳ == hoặc! = Được xác định bởi đối tượng (trừ khi tất nhiên bạn muốn sử dụng chúng ...)

Để không sử dụng null if (obj is object)(hoặc if (!(obj is null)))


1
Tôi tự hỏi là có "không null"? (trăn sẽ nói obj is not null)
sehe 7/07/18

1
Tại sao điều đó tốt hơn nếu (obj! = Null) dễ đọc hơn
Orn Kristjansson

38
Chúc họ thực hiện if (obj aint null):(
Nick Bull

10
Vì không phải là không cóif (obj is object)
yatskovsky

3
@OrnKristjansson vì! = Và == có thể bị ghi đè.
mitchellJ

61

C # 6 có kiểm tra null đơn âm :)

trước:

if (points != null) {
    var next = points.FirstOrDefault();
    if (next != null && next.X != null) return next.X;
}   
return -1;

sau:

var bestValue = points?.FirstOrDefault()?.X ?? -1;

7
Bởi vì "ý kiến ​​chỉ có thể được chỉnh sửa trong 5 phút"? Gì? Dù sao đi nữa ... Khi tôi bắt đầu ... Tôi đến đây để tìm kiếm một cú pháp tốt hơn để diễn đạt result = myObject == null ? null : myObject.SomePropertyvà ví dụ của bạn khiến tôi không thể viết được result = myObject?.SomeProperty. Đàn ông!! Đó là lén lút. Tôi vẫn thích viết mã ...
Adam Cox

27

DataList của bạn là null vì nó chưa được khởi tạo, đánh giá theo mã bạn đã đăng.

Thử:

public List<Object> dataList = new List<Object>();
public  bool AddData(ref Object data)
bool success = false;
try
{
    if (!data.Equals(null))   // I've also used if(data != null) which hasn't worked either
    {
       dataList.Add(data);                      //NullReferenceException occurs here
       success = doOtherStuff(data);
    }
}
catch (Exception e)
{
    throw new Exception(e.ToString());
}
return success;

}


3
Ngoài ra, chỉ cần thêm, nếu dữ liệu là null, nó sẽ không gặp sự cố, bạn có thể thêm null vào Danh sách <Object>.
DaveShaw

7
Nhưng cố gắng làm .Equals trên null sẽ ném một ngoại lệ. Nên làm! = Null
glosrob

@glosrob: À !! Thật là một sự giám sát! Tôi đã nghĩ rằng NullReferenceException là từ đối tượng .. không phải là danh sách! Tôi mới sử dụng c # và tôi nghĩ rằng có một cách đặc biệt để kiểm tra null trong c #!
nhà phát triển

Điều đó cũng vậy, nhưng tôi thấy Ed S. đã che nó.
DaveShaw

1
@DaveShaw: Cảm ơn vì đã ngẩng cao đầu. Tôi muốn tránh một đối tượng null được thêm vào để xử lý sau, vì vậy tôi vẫn sẽ kiểm tra. :)
nhà phát triển

19

[Đã chỉnh sửa để phản ánh gợi ý của @ kelton52]

Cách đơn giản nhất là làm object.ReferenceEquals(null, data)

(null==data)KHÔNG được đảm bảo để làm việc:

class Nully
{
    public static bool operator ==(Nully n, object o)
    {
        Console.WriteLine("Comparing '" + n + "' with '" + o + "'");
        return true;
    }
    public static bool operator !=(Nully n, object o) { return !(n==o); }
}
void Main()
{
    var data = new Nully();
    Console.WriteLine(null == data);
    Console.WriteLine(object.ReferenceEquals(null, data));
}

Sản xuất:

So sánh '' với 'Nully'

Thật

Sai


1
Trên thực tế tôi chỉ thử điều này và nhận xét 'Ưu điểm ngụ ý là nó bỏ qua mọi phần ghi đè có thể có trong lớp dữ liệu, như "toán tử! =".' Có vẻ như không đúng.
Kelly Elton

9

Không, bạn nên sử dụng !=. Nếu datathực sự là null thì chương trình của bạn sẽ gặp sự cố với NullReferenceExceptionkết quả của việc cố gắng gọi Equalsphương thức trên null. Cũng nhận ra rằng, nếu bạn đặc biệt muốn kiểm tra sự bình đẳng tham chiếu, bạn nên sử dụng Object.ReferenceEqualsphương thức này vì bạn không bao giờ biết cách Equalsthực hiện.

Chương trình của bạn bị sập vì không dataListcó giá trị vì bạn không bao giờ khởi tạo nó.


7

Vấn đề trong trường hợp này không phải datalà null. Đó là dataListbản thân nó là null.

Ở nơi bạn khai báo, dataListbạn nên tạo một Listđối tượng mới và gán nó cho biến.

List<object> dataList = new List<object>();

5

Ngoài câu trả lời @Jose Ortega , cách tốt hơn để sử dụng phương thức mở rộng

 public static bool IsNull(this object T)
     {
        return T == null;
     } 

Và sử dụng IsNullphương thức cho tất cả các đối tượng như:

object foo = new object(); //or any object from any class
if (foo.IsNull())
   {
     // blah blah //
   }

1
Tại sao return T == null ? true : false;và không chỉ return T == null;?
md2perpe

1
Tôi không chắc là tôi đồng ý. Có vẻ lạ khi gọi một phương thức trên một đối tượng để kiểm tra xem nó có rỗng không. Nếu không biết nó là một phương thức mở rộng, bạn sẽ nghĩ rằng nó sẽ đưa ra một ngoại lệ tham chiếu null.
Jamie Twells

Hoàn toàn có thể xác nhận rằng Jamie là chính xác - điều này sẽ không hoạt động. Tôi biết bởi vì tôi đã có một khoảnh khắc dũng cảm và đã viết một phương thức mở rộng tương tự: P Mã luôn ném một ngoại lệ tham chiếu null, nó hoàn toàn sẽ không đi vào phương thức mở rộng.
James King

Thực tế tôi muốn nói rằng bạn có thể làm điều đó với phương pháp gia hạn ... có thể mã có một số vấn đề và có thể cải thiện!
Ali

Bạn có thể gọi một phương thức mở rộng trên một đối tượng null; bạn chỉ cần so sánh T (trong trường hợp này) với null để cẩn thận. Jamie nói đúng, tuy nhiên, nó có vẻ kỳ quặc.
Tim Barrass

3

Kể từ C # 8, bạn có thể sử dụng mẫu thuộc tính 'trống' (có khớp mẫu ) để đảm bảo một đối tượng không rỗng:

if (obj is { })
{
    // 'obj' is not null here
}

Cách tiếp cận này có nghĩa là " nếu đối tượng tham chiếu một thể hiện của một cái gì đó " (nghĩa là nó không phải là null).

Bạn có thể nghĩ về điều này như đối nghịch với : if (obj is null).... cái này sẽ trả về true khi đối tượng không tham chiếu một thể hiện của cái gì đó.

Để biết thêm thông tin về các mẫu trong C # 8.0 đọc tại đây .


3

Kể từ C # 9 bạn có thể làm

if (obj is null) { ... }

Để không sử dụng null

if (obj is not object) { ... }

Nếu bạn cần ghi đè hành vi này sử dụng ==!=theo đó.


2

Jeffrey L Whitledge là đúng. Bản thân `dataList-Object của bạn là null.

Ngoài ra còn có một vấn đề khác với mã của bạn: Bạn đang sử dụng từ khóa ref, điều đó có nghĩa là dữ liệu đối số không thể rỗng! MSDN nói:

Một đối số được truyền cho một tham số ref trước tiên phải được khởi tạo. Điều này khác với bên ngoài, mà các đối số không cần phải được khởi tạo rõ ràng trước khi chúng được thông qua

Nó cũng không phải là một ý tưởng tốt để sử dụng thuốc generic với loại `Object. Generics nên tránh đấm bốc / unboxing và cũng đảm bảo an toàn loại. Nếu bạn muốn một loại phổ biến làm cho phương thức của bạn chung chung. Cuối cùng, mã của bạn sẽ trông như thế này:

public class Foo<T> where T : MyTypeOrInterface {

      public List<T> dataList = new List<T>();

      public bool AddData(ref T data) {
        bool success = false;
        try {
          dataList.Add(data);                   
          success = doOtherStuff(data);
        } catch (Exception e) {
          throw new Exception(e.ToString());
        }
        return success;
      }

      private bool doOtherStuff(T data) {
        //...
      }
    }

2

Như những người khác đã chỉ ra, nó không phải datanhưng có khả năng là như dataListvậy null. Thêm vào đó...

catch- throwlà một antipotype mà hầu như luôn luôn khiến tôi muốn ném lên mỗi khi tôi nhìn thấy nó. Hãy tưởng tượng rằng một cái gì đó đi sai sâu trong một cái gì đó doOtherStuff()gọi. Tất cả bạn nhận lại là một Exceptionđối tượng, ném throwvào AddData(). Không có dấu vết ngăn xếp, không có thông tin cuộc gọi, không có trạng thái, không có gì để chỉ ra nguồn gốc thực sự của vấn đề, trừ khi bạn đi vào và chuyển trình gỡ lỗi của bạn để phá vỡ ngoại lệ được ném chứ không phải ngoại lệ được xử lý. Nếu bạn đang bắt gặp một ngoại lệ và chỉ ném lại theo bất kỳ cách nào , đặc biệt nếu mã trong khối thử theo bất kỳ cách nào không cần thiết, hãy tự mình (và các đồng nghiệp của bạn, hiện tại và tương lai) ủng hộ và ném ra toàn bộ try- catchkhối . Được cấp,throw;là tốt hơn so với các lựa chọn thay thế, nhưng bạn vẫn đang tự cho mình (hoặc bất cứ ai khác đang cố gắng sửa một lỗi trong mã) hoàn toàn đau đầu không cần thiết. Điều này không có nghĩa là try-Catch-throw nhất thiết là xấu xa, miễn là bạn làm điều gì đó có liên quan với đối tượng ngoại lệ được ném bên trong khối bắt.

Sau đó, có những vấn đề tiềm ẩn của việc bắt Exceptionở nơi đầu tiên, nhưng đó là một vấn đề khác, đặc biệt là trong trường hợp cụ thể này, bạn ném một ngoại lệ.

Một điều nữa khiến tôi thấy nguy hiểm hơn một chút là nó datacó khả năng thay đổi giá trị trong quá trình thực thi chức năng, vì bạn đang chuyển qua tham chiếu. Vì vậy, kiểm tra null có thể vượt qua nhưng trước khi mã được thực hiện bất cứ điều gì với giá trị, nó đã thay đổi - có lẽ là null. Tôi không tích cực nếu điều này có liên quan hay không (có thể không), nhưng có vẻ đáng để theo dõi.


2
  public static bool isnull(object T)
  {
      return T == null ? true : false;
  }

sử dụng:

isnull(object.check.it)

Sử dụng có điều kiện:

isnull(object.check.it) ? DoWhenItsTrue : DoWhenItsFalse;

Cập nhật (cách khác) cập nhật ngày 31/8/2017. Cảm ơn các bình luận.

public static bool isnull(object T)
{
    return T ? true : false;
}

5
cond ? true : false;là hoàn toàn tương đương với chỉ cond. Điều này không thêm gì.
lericson

Tôi xin lỗi nhưng nếu bạn kiểm tra chức năng thì nó phải trả về giá trị bool. Tôi đang làm chủ nghĩa hình thức. Vì vậy, hãy kiểm tra lại
Jose Ortega

3
anh ta có nghĩa là return T == null;cũng trả lại một boolean!
MQoder

Tôi biết những gì anh ấy nói. ty
Jose Ortega

1
Thay vì return T == null ? true : false;chỉ sử dụng return T == null;.
md2perpe

1

Bất cứ khi nào bạn đang tạo các đối tượng của lớp, bạn phải kiểm tra xem đối tượng có rỗng hay không bằng cách sử dụng mã dưới đây.

Ví dụ: object1 là đối tượng của lớp

void myFunction(object1)
{
  if(object1!=null)
  {
     object1.value1 //If we miss the null check then here we get the Null Reference exception
  }
}

0

Tôi chỉ làm theo một phương thức mà chúng ta thường làm theo trong tập lệnh java. Để chuyển đổi đối tượng thành chuỗi và sau đó kiểm tra xem chúng có null không.

var obj = new Object();
var objStr = obj.ToString();
if (!string.IsNullOrEmpty(objStr)){
  // code as per your needs
}

0

Tôi đã làm đơn giản hơn (cách tích cực) và nó dường như hoạt động tốt.

Vì bất kỳ loại "đối tượng" nào cũng ít nhất là một đối tượng


    if (MyObj is Object)
    {
            //Do something .... for example:  
            if (MyObj is Button)
                MyObj.Enabled = true;
    }
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.