ตรวจสอบว่าวัตถุเป็นโมฆะใน C #


226

ฉันต้องการป้องกันการประมวลผลเพิ่มเติมบนวัตถุหากเป็นโมฆะ

ในรหัสต่อไปนี้ฉันตรวจสอบว่าวัตถุเป็นโมฆะโดยอย่างใดอย่างหนึ่ง:

if (!data.Equals(null))

และ

if (data != null)

แต่ผมได้รับที่NullReferenceException dataList.Add(data)หากวัตถุนั้นเป็นโมฆะมันไม่ควรที่จะใส่คำสั่งif-state!

ดังนั้นฉันถามว่านี่เป็นวิธีที่เหมาะสมในการตรวจสอบว่าวัตถุเป็นโมฆะ:

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;
}

หากนี่เป็นวิธีที่เหมาะสมในการตรวจสอบว่าวัตถุนั้นเป็นโมฆะฉันกำลังทำอะไรผิด (ฉันจะป้องกันการประมวลผลเพิ่มเติมบนวัตถุเพื่อหลีกเลี่ยง NullReferenceException) ได้อย่างไร


13
คุณควรใช้throw e;กับthrow new Exception(e.ToString());
ห้าม

17
ใน C # คุณควรใช้!= nullในการตรวจสอบโมฆะของคุณเสมอ .Equalsจะโยนข้อยกเว้นเสมอหากวัตถุนั้นเป็นโมฆะ
Kyle Trauberman

42
@Nix: throw e;ไม่ดีขึ้นมาก throw;ในทางกลับกัน ...
Jon

4
@developer: e.ToString()จะสร้างสตริงที่รวมถึงข้อความแสดงข้อผิดพลาดเท่านั้น แต่ยังรวมถึงสตริงทั้งหมดInnerExceptionsและการติดตามสแต็ก นั่นเป็นข้อความข้อยกเว้นที่อ้วนมาก ๆ หากคุณ (ถูกต้อง) throw;ต้องการที่จะรักษาข้อมูลนี้และเก็บที่มันอยู่ให้ใช้เพียง
Jon

14
การลอง / จับไม่ได้ทำอะไรเลยในขณะนี้ ทุกคนพูดเพียงแค่ใช้ "โยน" แต่ถ้าคุณไม่ได้ทำอะไรเลยยกเว้น แต่โยนอีกครั้งทำไมมีบล็อกลอง / catch เลย โดยปกติคุณจะได้รับการยกเว้นเพื่อจัดการกับมันอย่างสง่างามทำความสะอาดทรัพยากร (ดีกว่าด้วยประโยค "ในที่สุด") หรือทำการบันทึกบางอย่างก่อนที่จะทำการยกเว้นอีกครั้ง สิ่งเหล่านี้ไม่ได้เกิดขึ้นในรหัสนี้ดังนั้นจึงไม่จำเป็นต้องลอง / จับเลย
David Peterson

คำตอบ:


252

มันไม่ได้เป็นdataที่มีแต่nulldataList

คุณต้องสร้างด้วย

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

ได้ดียิ่งขึ้น: privateเนื่องจากเป็นข้อมูลที่ทำให้มัน และหากไม่มีสิ่งใดขวางกั้นคุณให้ทำเช่นreadonlyนั้น การปฏิบัติที่ดีเพียง

นอกเหนือ

วิธีที่ถูกต้องในการตรวจสอบความif(data != null)ว่างเปล่าคือ การตรวจสอบประเภทนี้เป็นที่แพร่หลายสำหรับประเภทการอ้างอิง แม้จะNullable<T>แทนที่โอเปอเรเตอร์ความเท่าเทียมกันจะเป็นวิธีที่สะดวกกว่าในการแสดงnullable.HasValueเมื่อตรวจสอบความว่างเปล่า

ถ้าคุณทำif(!data.Equals(null))แล้วคุณจะได้รับถ้าNullReferenceException data == nullซึ่งเป็นเรื่องตลกตั้งแต่หลีกเลี่ยงข้อยกเว้นนี้คือเป้าหมายในตอนแรก

คุณกำลังทำสิ่งนี้อยู่:

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

มันไม่ดีอย่างแน่นอน ฉันสามารถจินตนาการได้ว่าคุณใส่มันไว้ที่นั่นเพื่อให้คุณสามารถเจาะเข้าไปในตัวดีบั๊กขณะที่ยังอยู่ในวิธีการซึ่งในกรณีนี้ไม่สนใจย่อหน้านี้ มิฉะนั้นอย่าจับข้อยกเว้นเพื่ออะไร และถ้าคุณทำ rethrow throw;พวกเขาโดยใช้เพียง


5
ฉันเคยเห็นObject.ReferenceEquals (obj, null)เพื่อจุดประสงค์นี้ มันคือการหลีกเลี่ยงการแทนที่ความเท่าเทียมกัน?
Luca

2
@LucaPiccioni ฉันเคยใช้มันเพื่อป้องกัน value-type-complains เมื่อใช้ generics: geekality.net/2009/11/13/generics-and-checking-for-null
Svish

4
null != dataฉันชอบ การใส่ค่าคงที่อันดับแรกจะเปลี่ยนชนิดของ bonehead null = dataให้เป็นข้อผิดพลาดของคอมไพเลอร์แทนที่จะเป็นการกำหนดโดยไม่ได้ตั้งใจ (ใช้ได้กับ==.)
jpmc26

6
@ jpmc26: ใน C # if (data = null)เป็นข้อผิดพลาดในการรวบรวมเวลาอยู่แล้วดังนั้นแม้ว่าจะใช้เวลาหลายทศวรรษกว่าจะถึงที่นั่นเราก็ไม่จำเป็นต้องระวังอีกต่อไป แม้แต่คอมไพเลอร์ C ++ ก็สามารถสร้างคำเตือนเกี่ยวกับการมอบหมายที่ไม่ตั้งใจสำหรับรหัสนั้นได้อย่างง่ายดาย
Jon

Luca คุณยังสามารถหลีกเลี่ยงการแทนที่ความเท่าเทียมกันโดยการชี้ไปที่ 'object' ในการทดสอบ ในหลอดเลือดดำที่คล้ายกันคำตอบนี้ควรอ้างสิทธิ์สิ่งนี้แทน: "if ((วัตถุ) ข้อมูล! = null)" เนื่องจากจะหลีกเลี่ยงข้อผิดพลาดเมื่อความเท่าเทียมกันหมดไป
DAG

81

ใน C #> 7.0 ใช้

if (obj is null) ...

สิ่งนี้จะละเว้น == หรือ! = ที่กำหนดโดยวัตถุ (ยกเว้นว่าคุณต้องการใช้ ... )

สำหรับการใช้งานที่ไม่เป็นโมฆะif (obj is object)(หรือif (!(obj is null)))


1
ฉันสงสัยว่ามี "ไม่เป็นโมฆะ" หรือไม่ (หลามจะพูดobj is not null)
sehe

1
ทำไมถึงดีกว่าถ้า (obj! = null) ซึ่งอ่านได้ง่ายขึ้น
Orn Kristjansson

38
หวังว่าพวกเขาจะใช้if (obj aint null):(
นิคบูลล์

10
สำหรับไม่ใช่ค่าว่างนั่นคือif (obj is object)
yatskovsky

3
@OrnKristjansson เพราะ! = และ == สามารถแทนที่ได้
mitchellJ

61

C # 6 มีการตรวจสอบ monadic null :)

ก่อน:

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

หลังจาก:

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

7
เพราะ "ความคิดเห็นสามารถแก้ไขได้เพียง 5 นาที" อะไร? ทั้งนี้ ... ขณะที่ผมกำลังเดินทางไปยัง it..I มาที่นี่ในการค้นหาของไวยากรณ์ที่ดีกว่าในการแสดงและตัวอย่างของคุณปลายผมออกไปเขียนresult = myObject == null ? null : myObject.SomeProperty result = myObject?.SomePropertyชาย!! นั่นเป็นเรื่องลับๆล่อๆ ฉันยังคงรักการเขียนโค้ด ...
Adam Cox

27

DataList ของคุณเป็นโมฆะเนื่องจากยังไม่ได้สร้างอินสแตนซ์โดยพิจารณาจากรหัสที่คุณโพสต์

ลอง:

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
นอกจากนี้เพื่อเพิ่มถ้าข้อมูลเป็นโมฆะมันจะไม่ผิดพลาดคุณสามารถเพิ่ม null ลงในรายการ <Object>
DaveShaw

7
แต่พยายามที่จะทำ. ข้อ จำกัด ใน null จะโยนข้อยกเว้น ควรทำอย่างไร! = null
glosrob

@glosrob: อ่า !! ช่างเป็นผู้กำกับ! ฉันคิดว่า NullReferenceException มาจากวัตถุ .. ไม่ใช่รายการ! ฉันใหม่กับ c # และฉันคิดว่ามีวิธีพิเศษในการตรวจสอบ null ใน c #!
นักพัฒนา

เช่นกัน แต่ฉันเห็นเอ็ดเอสได้ครอบคลุมมัน
DaveShaw

1
@DaveShaw: ขอบคุณสำหรับหัวขึ้น ฉันต้องการหลีกเลี่ยงวัตถุว่างที่ถูกเพิ่มเข้ามาสำหรับการประมวลผลในภายหลังดังนั้นฉันจะยังคงตรวจสอบ :)
พัฒนา

19

[แก้ไขเพื่อสะท้อนคำใบ้โดย @ kelton52]

วิธีที่ง่ายที่สุดคือการทำ object.ReferenceEquals(null, data)

เนื่องจาก(null==data)ไม่รับประกันว่าจะทำงาน:

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

ผลิต:

เปรียบเทียบ '' กับ 'Nully'

จริง

เท็จ


1
ที่จริงฉันเพิ่งลองทำสิ่งนี้และคำพูด 'ข้อดีโดยนัยคือมันไม่สนใจการแทนที่ใด ๆ ที่อาจมีอยู่ในคลาสของข้อมูลเช่น "โอเปอเรเตอร์! =".' ดูเหมือนจะไม่จริง
Kelly Elton

9

!=ไม่มีคุณควรจะใช้ ถ้าdataเป็นจริง null แล้วโปรแกรมของคุณก็จะเกิดความผิดพลาดกับNullReferenceExceptionเป็นผลมาจากความพยายามที่จะเรียกวิธีการในการEquals nullนอกจากนี้ยังตระหนักว่าหากคุณต้องการตรวจสอบความเท่าเทียมกันโดยเฉพาะคุณควรใช้Object.ReferenceEqualsวิธีการที่คุณไม่เคยรู้ว่าEqualsมีการใช้งานอย่างไร

โปรแกรมของคุณทำงานล้มเหลวเนื่องจากdataListเป็นโมฆะเนื่องจากคุณไม่เคยกำหนดค่าเริ่มต้น


7

ปัญหาในกรณีนี้ไม่ใช่ว่าdataเป็นโมฆะ มันคือdataListตัวของมันเองเป็นโมฆะ

ในสถานที่ที่คุณประกาศdataListคุณควรสร้างListวัตถุใหม่และกำหนดให้กับตัวแปร

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

5

นอกเหนือจาก@Jose Ortegaคำตอบแล้วมันยังดีกว่าสำหรับวิธีการใช้งานส่วนขยาย

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

และใช้IsNullวิธีการสำหรับวัตถุทั้งหมดเช่น:

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

1
ทำไมreturn T == null ? true : false;และไม่เพียงreturn T == null;?
md2perpe

1
ฉันไม่แน่ใจว่าฉันเห็นด้วย มันดูแปลกที่จะเรียกใช้เมธอดบนวัตถุเพื่อตรวจสอบว่ามันเป็นโมฆะหรือไม่ โดยไม่ทราบว่ามันเป็นวิธีการขยายที่คุณจะคิดว่ามันจะโยนข้อยกเว้นอ้างอิงเป็นโมฆะ
Jamie Twells

สามารถยืนยันได้อย่างสมบูรณ์ว่าเจมี่ถูกต้อง - สิ่งนี้จะไม่ทำงาน ฉันรู้เพราะฉันมีช่วงเวลาที่กระต่ายป่าและเขียนวิธีการขยายที่คล้ายกัน: P รหัสมักจะโยนข้อยกเว้นการอ้างอิงเป็นโมฆะมันจะไม่เข้าสู่วิธีการขยายอย่างแน่นอน
James King

ที่จริงฉันอยากบอกว่าคุณทำได้ด้วยวิธีการ extention ... อาจเป็นรหัสที่มีปัญหาและสามารถปรับปรุงได้!
อาลี

คุณสามารถเรียกใช้เมธอดส่วนขยายบนวัตถุ null ได้ คุณเพียงแค่ต้องเปรียบเทียบ T (ในกรณีนี้) กับ null เพื่อระวัง เจมี่พูดถูก แต่มันดูแปลก ๆ
ทิม Barrass

3

ตั้งแต่C # 8คุณสามารถใช้รูปแบบคุณสมบัติ 'ว่างเปล่า' (พร้อมการจับคู่รูปแบบ ) เพื่อให้แน่ใจว่าวัตถุไม่เป็นโมฆะ:

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

วิธีการนี้หมายถึง " ถ้าวัตถุอ้างอิงถึงอินสแตนซ์ของบางสิ่งบางอย่าง " (เช่นมันไม่ใช่โมฆะ)

คุณสามารถคิดได้ว่าสิ่งนี้เป็นสิ่งที่ตรงกันข้ามกับ: if (obj is null).... ซึ่งจะส่งกลับจริงเมื่อวัตถุไม่ได้อ้างอิงตัวอย่างของบางสิ่งบางอย่าง

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับรูปแบบใน C # 8.0 อ่านที่นี่


3

ตั้งแต่C # 9คุณสามารถทำได้

if (obj is null) { ... }

สำหรับการใช้งานที่ไม่เป็นโมฆะ

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

หากคุณต้องการแทนที่พฤติกรรมนี้ให้ใช้==และ!=ตาม


2

Jeffrey L Whitledge ถูกต้อง `dataList´-Object ของคุณเองเป็นโมฆะ

นอกจากนี้ยังมีปัญหาอีกประการเกี่ยวกับรหัสของคุณ: คุณกำลังใช้คำหลักอ้างอิงซึ่งหมายความว่าข้อมูลอาร์กิวเมนต์ไม่สามารถเป็นค่าว่างได้! MSDN พูดว่า:

อาร์กิวเมนต์ที่ส่งไปยังพารามิเตอร์ ref จะต้องเริ่มต้นก่อน สิ่งนี้แตกต่างจาก out ซึ่งอาร์กิวเมนต์ไม่จำเป็นต้องกำหนดค่าเริ่มต้นอย่างชัดเจนก่อนที่จะส่งผ่าน

ไม่ใช่ความคิดที่ดีที่จะใช้ยาสามัญกับประเภท `วัตถุ ' ยาสามัญควรหลีกเลี่ยงการชกมวย / ไม่ทำกล่องและยังมั่นใจในความปลอดภัยของประเภท หากคุณต้องการประเภททั่วไปให้วิธีการของคุณทั่วไป ในที่สุดโค้ดของคุณควรมีลักษณะดังนี้:

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

อย่างที่คนอื่น ๆ ชี้ไปแล้วมันไม่ได้dataแต่มีแนวโน้มdataListว่าจะเป็นเช่นนั้นnullเช่นนั้น นอกจากนั้น ...

catch- throwเป็นปฏิปักษ์ที่เกือบทำให้ฉันต้องการที่จะโยนขึ้นทุกครั้งที่ฉันเห็นมัน ลองนึกภาพว่ามีบางอย่างผิดปกติในสิ่งที่doOtherStuff()เรียก ทั้งหมดที่คุณได้รับกลับเป็นExceptionวัตถุโยนที่ในthrow AddData()ไม่มีการติดตามสแต็กไม่มีข้อมูลการโทรไม่มีสถานะไม่มีอะไรเลยที่จะบ่งชี้ถึงแหล่งที่มาของปัญหาที่แท้จริงเว้นแต่คุณจะเข้าไปในและเปลี่ยนดีบักเกอร์ของคุณเพื่อแยกข้อยกเว้นที่เกิดขึ้นแทนที่จะจัดการข้อยกเว้นไม่ได้ หากคุณกำลังจับข้อยกเว้นและเพียงแค่โยนมันอีกครั้งในทางใดโดยเฉพาะอย่างยิ่งถ้าโค้ดในบล็อกการทดลองนั้นเป็นวิธีที่ไม่น่าสนใจให้ทำด้วยตัวเอง (และเพื่อนร่วมงานของคุณในปัจจุบันและอนาคต)try - catchบล็อก . ที่ได้รับthrow;ดีกว่าทางเลือกอื่น แต่คุณยังคงให้ตัวเอง (หรือใครก็ตามที่พยายามแก้ไขข้อบกพร่องในรหัส) อาการปวดหัวที่ไม่จำเป็นทั้งหมด นี่ไม่ได้เป็นการบอกว่าการลองจับการโยนนั้นเป็นสิ่งที่เลวร้ายตราบใดที่คุณทำบางสิ่งที่เกี่ยวข้องกับวัตถุยกเว้นที่ถูกโยนเข้าไปในบล็อกการจับ

จากนั้นมีปัญหาที่อาจเกิดขึ้นจากการถูกจับExceptionในตอนแรก แต่นั่นเป็นอีกเรื่องหนึ่งโดยเฉพาะอย่างยิ่งเนื่องจากในกรณีนี้คุณต้องยกเว้น

อีกสิ่งที่ทำให้ฉันเป็นอันตรายมากกว่าเล็กน้อยคือdataอาจเปลี่ยนค่าระหว่างการทำงานของฟังก์ชั่นเนื่องจากคุณกำลังผ่านการอ้างอิง ดังนั้นการตรวจสอบเป็นโมฆะอาจจะผ่าน แต่ก่อนรหัสที่ได้รับไปทำอะไรที่มีค่าก็เปลี่ยนแปลง - nullบางทีอาจจะ ฉันไม่คิดว่ามันจะเป็นสิ่งที่น่ากังวลหรือไม่ (อาจไม่ใช่) แต่มันก็คุ้มค่าที่จะระวัง


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

ใช้:

isnull(object.check.it)

การใช้แบบมีเงื่อนไข:

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

อัปเดต (วิธีอื่น) อัปเดตเมื่อวันที่ 31/31/2560 ขอบคุณสำหรับความคิดเห็น

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

5
cond ? true : false;condเป็นสมบูรณ์เทียบเท่ากับเพียง สิ่งนี้ไม่ช่วยอะไรเลย
lericson

ฉันขอโทษ แต่ถ้าคุณตรวจสอบฟังก์ชั่นมันจะต้องส่งกลับค่าบูล ฉันกำลังทำพิธีการ ตรวจสอบอีกครั้ง
Jose Ortega

3
เขาหมายถึงreturn T == null;ส่งคืนบูลีนด้วย!
MQoder

ฉันรู้ว่าคุณกำลังพูดอะไร ty
Jose Ortega

1
แทนการใช้เพียงreturn T == null ? true : false; return T == null;
md2perpe

1

เมื่อใดก็ตามที่คุณสร้างวัตถุของคลาสคุณต้องตรวจสอบว่าวัตถุนั้นเป็นโมฆะหรือไม่ใช้รหัสด้านล่าง

ตัวอย่าง: object1 เป็นวัตถุของคลาส

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

0

ฉันเพิ่งทำตามวิธีที่เรามักจะตามมาในจาวาสคริปต์ ในการแปลงวัตถุเป็นสตริงแล้วตรวจสอบว่าเป็นวัตถุว่างหรือไม่

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

0

ฉันทำได้ง่ายขึ้น (ทางบวก) และดูเหมือนว่าจะทำงานได้ดี

ตั้งแต่ "วัตถุ" ชนิดใดเป็นอย่างน้อยวัตถุ


    if (MyObj is Object)
    {
            //Do something .... for example:  
            if (MyObj is Button)
                MyObj.Enabled = true;
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.