c# - ما هو نولريفيرانسكسيبتيون، وكيف يمكنني إصلاحه؟


لدي بعض التعليمات البرمجية وعندما ينفذ، فإنه يلقي NullReferenceException ، قائلا:

مرجع كائن لم يتم تعيين إلى مثيل كائن.

ماذا يعني هذا، وماذا يمكنني أن أفعل لإصلاح هذا الخطأ؟




Answers


ما هو السبب؟

الحد الأدنى

أنت تحاول استخدام شيء null (أو Nothing في VB.NET). وهذا يعني أنك إما تعيينه إلى null ، أو أنك لم تقم بتعيينها مطلقا على أي شيء على الإطلاق.

مثل أي شيء آخر، لا يحصل على مرور null حولها. إذا كان null في الأسلوب "A"، يمكن أن يكون هذا الأسلوب "B" مرت null إلى الأسلوب "A".

بقية هذه المقالة يذهب إلى مزيد من التفاصيل ويظهر الأخطاء التي العديد من المبرمجين غالبا ما تجعل التي يمكن أن تؤدي إلى NullReferenceException .

اكثر تحديدا

وقت التشغيل رمي NullReferenceException يعني دائما نفس الشيء: كنت تحاول استخدام مرجع، والمرجعية لم يتم تهيئة (أو تم تهيئة مرة واحدة ، ولكن لم يعد تهيئة).

وهذا يعني أن المرجع null ، ولا يمكنك الوصول إلى الأعضاء (مثل الأساليب) من خلال مرجع null . أبسط حالة:

string foo = null;
foo.ToUpper();

سيؤدي هذا إلى رمي NullReferenceException في السطر الثاني لأنه لا يمكن استدعاء أسلوب المثيل ToUpper() على مرجع string يشير إلى null .

التصحيح

كيف تجد مصدر NullReferenceException ؟ وبصرف النظر عن النظر في الاستثناء نفسه، والتي سيتم طرحها بالضبط في المكان الذي يحدث فيه، القواعد العامة للتصحيح في فيسوال ستوديو تطبيق: وضع نقاط التوقف الاستراتيجية وفحص المتغيرات الخاصة بك ، إما عن طريق تحوم الماوس فوق أسمائهم، وفتح ( سريعة) نافذة ووتش أو باستخدام مختلف لوحات التصحيح مثل السكان المحليين والسيارات.

إذا كنت ترغب في معرفة مكان الإشارة أو لم يتم تعيينها، انقر بزر الماوس الأيمن فوق اسمها وحدد "البحث عن كافة المراجع". يمكنك ثم وضع نقطة توقف في كل موقع وجدت وتشغيل البرنامج مع المصحح المرفقة. في كل مرة يكسر المصحح على نقطة التوقف هذه، تحتاج إلى تحديد ما إذا كنت تتوقع أن يكون المرجع غير فارغ، وفحص المتغير والتحقق من أنه يشير إلى مثيل عندما تتوقع ذلك.

من خلال اتباع تدفق البرنامج بهذه الطريقة، يمكنك العثور على الموقع حيث يجب أن يكون المثال لاغية، ولماذا لم يتم تعيين بشكل صحيح.

أمثلة

بعض السيناريوهات الشائعة حيث يمكن طرح الاستثناء:

عام

ref1.ref2.ref3.member

إذا كانت RE1 أو ref2 أو ref3 فارغة، فستحصل على NullReferenceException . إذا كنت ترغب في حل المشكلة، ثم معرفة أي واحد هو نول من خلال إعادة كتابة التعبير إلى ما يعادلها أبسط:

var r1 = ref1;
var r2 = r1.ref2;
var r3 = r2.ref3;
r3.member

على وجه التحديد، في HttpContext.Current.User.Identity.Name ، يمكن أن يكون HttpContext.Current فارغة أو يمكن أن تكون الخاصية User فارغة أو يمكن أن تكون الخاصية Identity فارغة.

حالات الفئة

عند إنشاء متغير من نوع مرجع (فئة)، يتم تعيين افتراضيا إلى null .

public class Book {
    public string Title { get; set; }
}
public class Example {
    public void Foo() {
        Book b1;
        string title = b1.Title; // You never initialized the b1 variable.
                                    // there is no book to get the title from.
    }
}

يجب إما تهيئة متغيرات نوع الفئة أو تعيينها إلى مثيل فئة موجود بالفعل. تتم عملية التهيئة باستخدام الكلمة الرئيسية new .

Book b1 = new Book();

غير مباشر

public class Person {
    public int Age { get; set; }
}
public class Book {
    public Person Author { get; set; }
}
public class Example {
    public void Foo() {
        Book b1 = new Book();
        int authorAge = b1.Author.Age; // You never initialized the Author property.
                                       // there is no Person to get an Age from.
    }
}

إذا كنت ترغب في تجنب مرجع نول (الطفل)، يمكنك تهيئة في منشئ الكائن الأصل (كتاب).

وينطبق الشيء نفسه على أدوات تهيئة العناصر المتداخلة:

Book b1 = new Book { Author = { Age = 45 } };

في حين يتم استخدام الكلمة الرئيسية new ، إلا أنه ينشئ مثيل جديد من Book ، ولكن ليس مثيل جديد من Person ، وبالتالي فإن Author لا يزال null .

مجموعة مصفوفة

int[] numbers = null;
int n = numbers[0]; // numbers is null. There is no array to index.

صفيف عناصر

Person[] people = new Person[5];
people[0].Age = 20 // people[0] is null. The array was allocated but not
                   // initialized. There is no Person to set the Age for.

صفائف خشنة

long[][] array = new long[1][];
array[0][0] = 3; // is null because only the first dimension is yet initialized.
                 // Use array[0] = new long[2]; first.

جمع / قائمة / قاموس

Dictionary<string, int> agesForNames = null;
int age = agesForNames["Bob"]; // agesForNames is null.
                               // There is no Dictionary to perform the lookup.

متغير النطاق (غير مباشر / مؤجل)

public class Person {
    public string Name { get; set; }
}
var people = new List<Person>();
people.Add(null);
var names = from p in people select p.Name;
string firstName = names.First(); // Exception is thrown here, but actually occurs
                                  // on the line above.  "p" is null because the
                                  // first element we added to the list is null.

أحداث

public class Demo
{
    public event EventHandler StateChanged;

    protected virtual void OnStateChanged(EventArgs e)
    {        
        StateChanged(this, e); // Exception is thrown here 
                               // if no event handlers have been attached
                               // to StateChanged event
    }
}

اتفاقيات التسمية السيئة:

إذا قمت بتسمية الحقول بشكل مختلف عن السكان المحليين، فقد تكون قد أدركت أنك لم تقم بتهيئة الحقل.

public class Form1 {
    private Customer customer;

    private void Form1_Load(object sender, EventArgs e) {
        Customer customer = new Customer();
        customer.Name = "John";
    }

    private void Button_Click(object sender, EventArgs e) {
        MessageBox.Show(customer.Name);
    }
}

يمكن حل هذا عن طريق اتباع الاتفاقية إلى حقول البادئة مع تسطير أسفل السطر:

private Customer _customer;

دورة حياة صفحة ASP.NET:

public partial class Issues_Edit : System.Web.UI.Page
{
    protected TestIssue myIssue;

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            // Only called on first load, not when button clicked
            myIssue = new TestIssue(); 
        }
    }

    protected void SaveButton_Click(object sender, EventArgs e)
    {
        myIssue.Entry = "NullReferenceException here!";
    }
}

قيم جلسة ASP.NET

// if the "FirstName" session value has not yet been set,
// then this line will throw a NullReferenceException
string firstName = Session["FirstName"].ToString();

ASP.NET مفك نماذج عرض فارغة

إذا حدث الاستثناء عند الرجوع إلى خاصية من @Model في عرض ASP.NET مفك، تحتاج إلى فهم أن يتم تعيين Model في طريقة عملك، عند return طريقة عرض. عند إرجاع نموذج فارغ (أو خاصية نموذج) من وحدة التحكم الخاصة بك، يحدث الاستثناء عند الوصول إلى وجهات النظر:

// Controller
public class Restaurant:Controller
{
    public ActionResult Search()
    {
         return View();  // Forgot the provide a Model here.
    }
}

// Razor view 
@foreach (var restaurantSearch in Model.RestaurantSearch)  // Throws.
{
}

<p>@Model.somePropertyName</p> <!-- Also throws -->

وف إنشاء السيطرة إنشاء والأحداث

يتم إنشاء الضوابط وف خلال الدعوة إلى InitializeComponent في الترتيب الذي تظهر في شجرة بصرية. سيتم رفع NullReferenceException في حالة الضوابط التي تم إنشاؤها في وقت مبكر مع معالجات الأحداث، وما إلى ذلك، التي تطلق أثناء InitializeComponent التي تشير إلى عناصر التحكم التي تم إنشاؤها في وقت متأخر.

فمثلا :

<Grid>
    <!-- Combobox declared first -->
    <ComboBox Name="comboBox1" 
              Margin="10"
              SelectedIndex="0" 
              SelectionChanged="comboBox1_SelectionChanged">
        <ComboBoxItem Content="Item 1" />
        <ComboBoxItem Content="Item 2" />
        <ComboBoxItem Content="Item 3" />
    </ComboBox>

    <!-- Label declared later -->
    <Label Name="label1" 
           Content="Label"
           Margin="10" />
</Grid>

هنا يتم إنشاء comboBox1 قبل label1 . إذا حاول كومبو Box1_SelectionChanged الإشارة إلى `label1، فلن يتم إنشاؤه بعد.

private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    label1.Content = comboBox1.SelectedIndex.ToString(); // NullReference here!!
}

تغيير ترتيب الإعلانات في زمل (أي إدراج label1 قبل label1 ، تجاهل قضايا فلسفة التصميم، على الأقل حل NullReferenceException هنا.

يلقي مع

var myThing = someObject as Thing;

هذا لا رمي إنفاليدكاستكسيبتيون ولكن إرجاع قيمة null عند فشل المدلى بها (وعندما سوموبجيكت هو نفسه نول). حتئ يكون على بينة من ذلك.

لينق فيرستوردفولت () و سينغلوردفولت ()

إصدارات عادي First() Single() استثناءات رمي ​​عندما لا يكون هناك شيء. ترجع الإصدارات "أوردفولت" فارغة في هذه الحالة. حتئ يكون على بينة من ذلك.

foreach

foreach رمي عند محاولة تكرارات جمع فارغة. عادة ما ينتج عن نتيجة null غير متوقعة من الأساليب التي تعيد المجموعات.

 List<int> list = null;    
 foreach(var v in list) { } // exception

مثال أكثر واقعية - حدد العقد من مستند شمل. سوف رمي إذا لم يتم العثور على العقد ولكن التصحيح الأولي يظهر أن جميع الخصائص صالحة:

 foreach (var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))

طرق لتجنب

تحقق صراحة من عدم وجود قيمة null وتجاهل القيم الفارغة.

إذا كنت تتوقع أن تكون الإشارة في بعض الأحيان فارغة، يمكنك التحقق من كونها null قبل الوصول إلى أعضاء المثيل:

void PrintName(Person p) {
    if (p != null) {
        Console.WriteLine(p.Name);
    }
}

تحقق صراحة من عدم وجود قيمة null وقدم قيمة افتراضية.

طرق استدعاء تتوقع إرجاع مثيل يمكن إرجاع null ، على سبيل المثال عندما لا يتم العثور على الكائن المطلوب. يمكنك اختيار إرجاع قيمة افتراضية عندما تكون هذه هي الحالة:

string GetCategory(Book b) {
    if (b == null)
        return "Unknown";
    return b.Category;
}

تحقق صراحة من عدم وجود نداء من مكالمات الطريقة ورمي استثناء مخصص.

يمكنك أيضا رمي استثناء مخصص، فقط للقبض عليه في رمز الدعوة:

string GetCategory(string bookTitle) {
    var book = library.FindBook(bookTitle);  // This may return null
    if (book == null)
        throw new BookNotFoundException(bookTitle);  // Your custom exception
    return book.Category;
}

استخدم Debug.Assert إذا كان يجب ألا تكون القيمة null ، للقبض على المشكلة في وقت سابق من حدوث الاستثناء.

عندما تعرف أثناء التطوير أن طريقة ربما يمكن، ولكن يجب أبدا العودة null ، يمكنك استخدام Debug.Assert() لكسر في أقرب وقت ممكن عندما يحدث:

string GetTitle(int knownBookID) {
    // You know this should never return null.
    var book = library.GetBook(knownBookID);  

    // Exception will occur on the next line instead of at the end of this method.
    Debug.Assert(book != null, "Library didn't return a book for known book ID.");

    // Some other code

    return book.Title; // Will never throw NullReferenceException in Debug mode.
}

على الرغم من أن هذا الاختيار لن ينتهي في بناء الإصدار الخاص بك ، مما تسبب في رمي NullReferenceException مرة أخرى عندما book == null في وقت التشغيل في وضع الإصدار.

استخدم GetValueOrDefault() لأنواع القيمة GetValueOrDefault() لتوفير قيمة افتراضية عندما تكون null .

DateTime? appointment = null;
Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now));
// Will display the default value provided (DateTime.Now), because appointment is null.

appointment = new DateTime(2022, 10, 20);
Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now));
// Will display the appointment date, not the default

استخدام عامل التجميع الفارغ: ?? [C #] أو If() [ف].

الاختزال لتوفير قيمة افتراضية عندما يتم مواجهة null :

IService CreateService(ILogger log, Int32? frobPowerLevel)
{
    var serviceImpl = new MyService(log ?? NullLog.Instance);

    // Note that the above "GetValueOrDefault()" can also be rewritten to use
    // the coalesce operator:
    serviceImpl.FrobPowerLevel = frobPowerLevel ?? 5;
}

استخدام عامل الشرط نول: ?. (متوفر في C # 6 و VB.NET 14):

ويسمى هذا أيضا أحيانا الملاحة الآمنة أو الفيس (بعد شكله) المشغل. إذا كان التعبير على الجانب الأيسر من المشغل فارغ، فلن يتم تقييم الجانب الأيمن، ويتم إرجاع نول بدلا من ذلك. وهذا يعني حالات مثل هذا:

var title = person.Title.ToUpper();

إذا كان الشخص ليس لديه عنوان، وهذا رمي استثناء لأنه يحاول استدعاء ToUpper على خاصية مع قيمة فارغة.

في C # 5 وأدناه، يمكن حراسة هذا مع:

var title = person.Title == null ? null : person.Title.ToUpper();

الآن سوف يكون متغير العنوان نول بدلا من رمي استثناء. يقدم C # 6 بنية أقصر لهذا:

var title = person.Title?.ToUpper();

سيؤدي هذا إلى تغيير متغير العنوان، ولا يتم إجراء المكالمة إلى ToUpper إذا كان person.Title null .

بطبيعة الحال، لا يزال لديك للتحقق من title ل نول أو استخدام عامل شرط نول جنبا إلى جنب مع عامل الانحلال فارغة ( ?? ) لتوفير قيمة افتراضية:

// regular null check
int titleLength = 0;
if (title != null)
    titleLength = title.Length; // If title is null, this would throw NullReferenceException

// combining the `?` and the `??` operator
int titleLength = title?.Length ?? 0;



استثناء نولريفيرانس - فيسوال باسيك

NullReference Exception ل فيسوال باسيك لا يختلف عن واحد في C # . بعد كل شيء، على حد سواء الإبلاغ عن نفس الاستثناء المحدد في. نيت فريميورك التي تستخدم على حد سواء. أسباب فريدة من نوعها ل فيسوال باسيك نادرة (ربما واحد فقط).

ستستخدم هذه الإجابة مصطلحات فيسوال باسيك، وبناء الجملة، والسياق. والأمثلة المستخدمة تأتي من عدد كبير من الأسئلة الماضية كومة تجاوز. هذا هو لتحقيق أقصى قدر من الأهمية باستخدام أنواع الحالات التي ينظر إليها في كثير من الأحيان في الوظائف. كما يتم تقديم تفسير أكثر قليلا لأولئك الذين قد يحتاجون إليها. ومن المرجح جدا أن يكون هناك مثال مشابه لك.

ملحوظة:

  1. هذا هو القائم على مفهوم: لا يوجد رمز لك للصق في المشروع الخاص بك. الغرض منه هو مساعدتك على فهم ما يسبب NullReferenceException (نري)، وكيفية العثور عليه، وكيفية إصلاحه، وكيفية تجنب ذلك. يمكن أن يسبب نري العديد من الطرق لذلك من غير المرجح أن يكون لقاء الوحيد الخاص بك.
  2. الأمثلة (من مشاركات ستاك أوفيرفلو) لا تظهر دائما أفضل طريقة للقيام بشيء ما في المقام الأول.
  3. عادة، يتم استخدام أبسط علاج.

المعنى الأساسي

رسالة "كائن غير محدد إلى مثيل كائن" يعني أنك تحاول استخدام كائن لم يتم تهيئة. هذا يتلخص في واحدة من هذه:

  • أعلنت الشفرة الخاصة بك متغير الكائن، ولكن لم تهيئته (إنشاء مثيل أو " مثيل " ذلك)
  • أي شيء يفترض رمزك أن تهيئة كائن، لم يفعل ذلك
  • ربما، رمز آخر يبطل قبل الأوان كائن لا يزال قيد الاستخدام

العثور على السبب

وبما أن المشكلة هي مرجع الكائن الذي Nothing ، فإن الجواب هو لفحصها لمعرفة أي واحد. ثم حدد لماذا لم يتم تهيئة. عقد الماوس فوق المتغيرات المختلفة و فيسوال ستوديو (فس) سوف تظهر قيمهم - الجاني سيكون Nothing .

يجب عليك أيضا إزالة أي كتل تري / كاتش من التعليمات البرمجية ذات الصلة، وخاصة تلك التي لا يوجد شيء في كتلة الصيد. سيؤدي هذا إلى تعطل التعليمات البرمجية عند محاولة استخدام كائن وهو Nothing . هذا هو ما تريد لأنه سيحدد الموقع الدقيق للمشكلة، ويسمح لك بتحديد الكائن المسببة لها.

و MsgBox في الصيد الذي يعرض Error while... سيكون من القليل من المساعدة. هذا الأسلوب يؤدي أيضا إلى أسئلة سيئة جدا المكدس تجاوز، لأنك لا يمكن أن تصف الاستثناء الفعلي، وجوه المعنية أو حتى خط التعليمات البرمجية حيث يحدث ذلك.

يمكنك أيضا استخدام Locals Window ( تصحيح -> ويندوز -> السكان المحليين ) لفحص الكائنات الخاصة بك.

بمجرد أن تعرف ما وأين المشكلة، فمن السهل إلى حد ما لإصلاح وأسرع من نشر سؤال جديد.

أنظر أيضا:

أمثلة وعلاجات

كائنات فئة / إنشاء مثيل

Dim reg As CashRegister
...
TextBox1.Text = reg.Amount         ' NRE

المشكلة هي أن Dim لا إنشاء كائن كاشرجيستر؛ فإنه يعلن فقط متغير اسمه reg من هذا النوع. إعلان متغير الكائن وإنشاء مثيل أمران مختلفان.

علاج

يمكن استخدام المشغل New كثير من الأحيان لإنشاء المثيل عند إعلانه:

Dim reg As New CashRegister        ' [New] creates instance, invokes the constructor

' Longer, more explicit form:
Dim reg As CashRegister = New CashRegister

عندما يكون مناسبا فقط لإنشاء المثيل لاحقا:

Private reg As CashRegister         ' Declare
  ...
reg = New CashRegister()            ' Create instance

ملاحظة: لا تستخدم Dim مرة أخرى في الإجراء، بما في ذلك منشئ ( Sub New ):

Private reg As CashRegister
'...

Public Sub New()
   '...
   Dim reg As New CashRegister
End Sub

سيؤدي هذا إلى إنشاء متغير محلي ، reg ، موجود فقط في هذا السياق (فرعي). المتغير reg مع مستوى وحدة Scope الذي سوف تستخدم في كل مكان آخر لا Nothing .

مفقود المشغل New هو السبب # 1 من NullReference Exceptions ينظر في الأسئلة المكدس تجاوز.

يحاول فيسوال باسيك لجعل العملية واضحة بشكل متكرر باستخدام New : استخدام مشغل New بإنشاء كائن جديد ويدعو Sub New - منشئ - حيث الكائن الخاص بك يمكن إجراء أي تهيئة أخرى.

ولكي تكون واضحة، يعلن Dim ( Dim Private ) عن متغير ونوعه فقط. يتم تحديد نطاق المتغير - سواء كان موجودا لوحدة / فئة بأكملها أو المحلية إلى إجراء - حيث أعلن. Private | Friend | Public يحدد Private | Friend | Public مستوى الوصول، وليس النطاق .

لمزيد من المعلومات، راجع:

المصفوفات

يجب أيضا إنشاء صفائف:

Private arr as String()

وقد تم الإعلان عن هذه المصفوفة فقط، لم يتم إنشاؤها. هناك عدة طرق لتهيئة مصفوفة:

Private arr as String() = New String(10){}
' or
Private arr() As String = New String(10){}

' For a local array (in a procedure) and using 'Option Infer':
Dim arr = New String(10) {}

ملاحظة: بدءا من فس 2010، عند تهيئة صفيف محلي باستخدام حرفي و Option Infer ، As <Type> و New إكستراشيونال اختيارية:

Dim myDbl As Double() = {1.5, 2, 9.9, 18, 3.14}
Dim myDbl = New Double() {1.5, 2, 9.9, 18, 3.14}
Dim myDbl() = {1.5, 2, 9.9, 18, 3.14}

يتم استنتاج نوع البيانات وحجم الصفيف من البيانات التي يتم تعيينها. لا تزال الإعلانات على مستوى الوحدة / الوحدة تتطلب As <Type> ويث Option Strict :

Private myDoubles As Double() = {1.5, 2, 9.9, 18, 3.14}

مثال: صفيف كائنات فئة

Dim arrFoo(5) As Foo

For i As Integer = 0 To arrFoo.Count - 1
   arrFoo(i).Bar = i * 10       ' Exception
Next

تم إنشاء مجموعة، ولكن الكائنات Foo في ذلك لم.

علاج

For i As Integer = 0 To arrFoo.Count - 1
    arrFoo(i) = New Foo()         ' Create Foo instance
    arrFoo(i).Bar = i * 10
Next

استخدام List(Of T) سيجعل من الصعب جدا أن يكون عنصر بدون كائن صالح:

Dim FooList As New List(Of Foo)     ' List created, but it is empty
Dim f As Foo                        ' Temporary variable for the loop

For i As Integer = 0 To 5
    f = New Foo()                    ' Foo instance created
    f.Bar =  i * 10
    FooList.Add(f)                   ' Foo object added to list
Next

لمزيد من المعلومات، راجع:

القوائم والمجموعات

مجموعات .NET (التي هناك العديد من الأصناف - القوائم، قاموس، وما إلى ذلك) يجب أيضا أن تكون مثبتة أو إنشاؤها.

Private myList As List(Of String)
..
myList.Add("ziggy")           ' NullReference

يمكنك الحصول على نفس الاستثناء لنفس السبب - تم إعلان myList فقط، ولكن لم يتم إنشاء أي مثيل. والعلاج هو نفسه:

myList = New List(Of String)

' Or create an instance when declared:
Private myList As New List(Of String)

والرقابة المشتركة هي فئة التي تستخدم مجموعة Type :

Public Class Foo
    Private barList As List(Of Bar)

    Friend Function BarCount As Integer
        Return barList.Count
    End Function

    Friend Sub AddItem(newBar As Bar)
        If barList.Contains(newBar) = False Then
            barList.Add(newBar)
        End If
    End Function

أي إجراء يؤدي إلى نري، لأن barList أعلن فقط، وليس barList . إنشاء مثيل Foo لن أيضا إنشاء مثيل barList الداخلي. وقد يكون القصد من ذلك هو القيام بذلك في المنشئ:

Public Sub New         ' Constructor
    ' Stuff to do when a new Foo is created...
    barList = New List(Of Bar)
End Sub

كما كان من قبل، وهذا غير صحيح:

Public Sub New()
    ' Creates another barList local to this procedure
     Dim barList As New List(Of Bar)
End Sub

لمزيد من المعلومات، راجع List(Of T) فئة .

كائنات موفر البيانات

العمل مع قواعد البيانات يعرض العديد من الفرص ل نولريفيرانس لأنه يمكن أن يكون هناك العديد من الكائنات ( Command ، Connection ، Transaction ، Dataset ، DataRows ، DataRows ....) في استخدام دفعة واحدة. ملاحظة: لا يهم أي مزود البيانات التي تستخدمها - ميسكل، سكل سيرفر، أوليدب، الخ - المفاهيم هي نفسها.

مثال 1

Dim da As OleDbDataAdapter
Dim ds As DataSet
Dim MaxRows As Integer

con.Open()
Dim sql = "SELECT * FROM tblfoobar_List"
da = New OleDbDataAdapter(sql, con)
da.Fill(ds, "foobar")
con.Close()

MaxRows = ds.Tables("foobar").Rows.Count      ' Error

كما كان من قبل، تم الإعلان عن كائن ds داتاسيت، ولكن لم يتم إنشاء مثيل أبدا. سيقوم DataAdapter بملء DataSet موجود، وليس إنشاء واحد. في هذه الحالة، لأن ds هو متغير محلي، إيد يحذرك من أن هذا قد يحدث:

عندما يعلن كمتغير وحدة نمطية / فئة، كما يبدو أنه هو الحال مع con ، لا يمكن للمعدي معرفة ما إذا تم إنشاء الكائن بواسطة إجراء أوبستريم. لا تتجاهل التحذيرات.

علاج

Dim ds As New DataSet

المثال 2

ds = New DataSet
da = New OleDBDataAdapter(sql, con)
da.Fill(ds, "Employees")

txtID.Text = ds.Tables("Employee").Rows(0).Item(1)
txtID.Name = ds.Tables("Employee").Rows(0).Item(2)

خطأ مطبعي مشكلة هنا: Employees مقابل Employee . لم يكن هناك DataTable المسمى "موظف" تم إنشاؤها، لذلك نتائج NullReferenceException تحاول الوصول إليه. هناك مشكلة محتملة أخرى هي افتراض وجود Items قد لا تكون كذلك عندما يتضمن سكل عبارة وير.

علاج

وبما أن هذا يستخدم جدول واحد، باستخدام Tables(0) سوف تجنب الأخطاء الإملائية. فحص Rows.Count أن تساعد أيضا:

If ds.Tables(0).Rows.Count > 0 Then
    txtID.Text = ds.Tables(0).Rows(0).Item(1)
    txtID.Name = ds.Tables(0).Rows(0).Item(2)
End If

Fill هو وظيفة إرجاع عدد Rows المتضررة التي يمكن أيضا اختبارها:

If da.Fill(ds, "Employees") > 0 Then...

المثال 3

Dim da As New OleDb.OleDbDataAdapter("SELECT TICKET.TICKET_NO,
        TICKET.CUSTOMER_ID, ... FROM TICKET_RESERVATION AS TICKET INNER JOIN
        FLIGHT_DETAILS AS FLIGHT ... WHERE [TICKET.TICKET_NO]= ...", con)
Dim ds As New DataSet
da.Fill(ds)

If ds.Tables("TICKET_RESERVATION").Rows.Count > 0 Then

سيقوم TableNames بتوفير TableNames كما هو موضح في المثال السابق، ولكنه لا يقوم بتحليل الأسماء من جدول سكل أو قاعدة البيانات. ونتيجة لذلك، ds.Tables("TICKET_RESERVATION") إلى جدول غير موجود.

العلاج هو نفسه، مرجع الجدول حسب الفهرس:

If ds.Tables(0).Rows.Count > 0 Then

أنظر أيضا داتاتابل كلاس .

مسارات الكائن / متداخلة

If myFoo.Bar.Items IsNot Nothing Then
   ...

رمز اختبار Items فقط في حين أن كلا myFoo و Bar قد يكون أيضا لا شيء. العلاج هو اختبار السلسلة بأكملها أو مسار الكائنات في وقت واحد:

If (myFoo IsNot Nothing) AndAlso
    (myFoo.Bar IsNot Nothing) AndAlso
    (myFoo.Bar.Items IsNot Nothing) Then
    ....

AndAlso مهم. لن يتم إجراء الاختبارات اللاحقة بمجرد مواجهة أول False . هذا يسمح التعليمات البرمجية بأمان 'حفر' في الكائن (ق) 'مستوى' واحد في وقت واحد، وتقييم myFoo.Bar فقط بعد (وإذا) myFoo يتم تحديد أن تكون صالحة. سلاسل الكائن أو المسارات يمكن الحصول طويلة جدا عند ترميز الأشياء المعقدة:

myBase.myNodes(3).Layer.SubLayer.Foo.Files.Add("somefilename")

لا يمكن الإشارة إلى أي شيء 'أسفل' من كائن null . وينطبق هذا أيضا على الضوابط:

myWebBrowser.Document.GetElementById("formfld1").InnerText = "some value"

هنا، يمكن أن يكون myWebBrowser أو Document لا شيء أو عنصر formfld1 قد لا تكون موجودة.

عناصر تحكم واجهة المستخدم

Dim cmd5 As New SqlCommand("select Cartons, Pieces, Foobar " _
     & "FROM Invoice where invoice_no = '" & _
     Me.ComboBox5.SelectedItem.ToString.Trim & "' And category = '" & _
     Me.ListBox1.SelectedItem.ToString.Trim & "' And item_name = '" & _
     Me.ComboBox2.SelectedValue.ToString.Trim & "' And expiry_date = '" & _
     Me.expiry.Text & "'", con)

من بين أمور أخرى، لا يتوقع هذا الرمز أن المستخدم قد لا يكون اختيار شيء في واحد أو أكثر من عناصر تحكم واجهة المستخدم. ListBox1.SelectedItem قد يكون Nothing ، لذلك ListBox1.SelectedItem.ToString يؤدي إلى نري.

علاج

التحقق من صحة البيانات قبل استخدامه (أيضا استخدام Option Strict و سكل المعلمات):

Dim expiry As DateTime         ' for text date validation
If (ComboBox5.SelectedItems.Count > 0) AndAlso
    (ListBox1.SelectedItems.Count > 0) AndAlso
    (ComboBox2.SelectedItems.Count > 0) AndAlso
    (DateTime.TryParse(expiry.Text, expiry) Then

    '... do stuff
Else
    MessageBox.Show(...error message...)
End If

بدلا من ذلك، يمكنك استخدام (ComboBox5.SelectedItem IsNot Nothing) AndAlso...

فيسوال باسيك فورمز

Public Class Form1

    Private NameBoxes = New TextBox(5) {Controls("TextBox1"), _
                   Controls("TextBox2"), Controls("TextBox3"), _
                   Controls("TextBox4"), Controls("TextBox5"), _
                   Controls("TextBox6")}

    ' same thing in a different format:
    Private boxList As New List(Of TextBox) From {TextBox1, TextBox2, TextBox3 ...}

    ' Immediate NRE:
    Private somevar As String = Me.Controls("TextBox1").Text

هذا هو وسيلة شائعة إلى حد ما للحصول على نري. في C #، اعتمادا على الكود الذي تم ترميزه، سوف إيد تقرير أن Controls غير موجودة في السياق الحالي، أو "لا يمكن الرجوع عضو غير ثابت". لذلك، إلى حد ما، وهذا هو الوضع ف-فقط. وهو أيضا معقد لأنه يمكن أن يؤدي إلى تتالي فشل.

لا يمكن تهيئة المصفوفات والمجموعات بهذه الطريقة. سيتم تشغيل هذا الرمز التهيئة قبل إنشاء منشئ Form أو Controls . كنتيجة لــ:

  • القوائم وجمع سيكون ببساطة فارغة
  • سيتضمن المصفوفة خمسة عناصر من لا شيء
  • سوف يؤدي تعيين somevar إلى نري فوري لأن ليس هناك شيء .Text الخاصية

وستؤدي عناصر صفيف الرجوع في وقت لاحق إلى نري. إذا قمت بذلك في Form_Load ، بسبب علة فردية، قد لا يبلغ إيد الاستثناء عندما يحدث. سيظهر الاستثناء في وقت لاحق عندما تحاول التعليمات البرمجية استخدام المصفوفة. هذا "الاستثناء الصامت" مفصل في هذا المنصب . لأغراضنا، والمفتاح هو أنه عندما يحدث كارثية أثناء إنشاء نموذج ( Sub New أو Form Load الحدث)، والاستثناءات قد لا يبلغ عنها، رمز يخرج الإجراء ويعرض فقط النموذج.

نظرا لأنه لن يتم تشغيل أي رمز آخر في الحدث " Form Load Sub New أو " Form Load بعد نري، يمكن ترك العديد من الأشياء الأخرى غير مهيأ.

Sub Form_Load(..._
   '...
   Dim name As String = NameBoxes(2).Text        ' NRE
   ' ...
   ' More code (which will likely not be executed)
   ' ...
End Sub

تجدر الإشارة إلى أن هذا ينطبق على أي من مراجع التحكم والمكونات التي تجعلها غير قانونية حيثما تكون:

Public Class Form1

    Private myFiles() As String = Me.OpenFileDialog1.FileName & ...
    Private dbcon As String = OpenFileDialog1.FileName & ";Jet Oledb..."
    Private studentName As String = TextBox13.Text

علاج جزئي

ومن الغريب أن ف لا توفر تحذيرا، ولكن العلاج هو أن تعلن الحاويات على مستوى النموذج، ولكن تهيئة لهم في شكل معالج الحدث الحمل عند وجود عناصر التحكم. يمكن القيام بذلك في Sub New طالما التعليمات البرمجية الخاصة بك بعد استدعاء InitializeComponent :

' Module level declaration
Private NameBoxes as TextBox()
Private studentName As String

' Form Load, Form Shown or Sub New:
'
' Using the OP's approach (illegal using OPTION STRICT)
NameBoxes = New TextBox() {Me.Controls("TextBox1"), Me.Controls("TestBox2"), ...)
studentName = TextBox32.Text           ' For simple control references

قد لا يكون رمز الصفيف خارج الغابة بعد. لن يتم العثور على عناصر التحكم الموجودة في عنصر التحكم في الحاوية (مثل GroupBox أو Panel ) في Me.Controls . فسيكون ذلك في مجموعة عناصر التحكم في تلك المجموعة أو مربع التخصيص. كما لن يتم إرجاع عنصر تحكم عندما يكون اسم عنصر التحكم خطأ إملائيا ( "TeStBox2" ). في مثل هذه الحالات، لن يتم تخزين Nothing مرة أخرى في تلك العناصر صفيف وسوف نري نتيجة عند محاولة الرجوع إليها.

وينبغي أن يكون من السهل العثور عليها الآن أن تعرف ما تبحث عنه:

"Button2" يقيم على Panel

علاج

بدلا من المراجع غير المباشرة بالاسم باستخدام مجموعة Controls في النموذج، استخدم مرجع التحكم:

' Declaration
Private NameBoxes As TextBox()

' Initialization -  simple and easy to read, hard to botch:
NameBoxes = New TextBox() {TextBox1, TextBox2, ...)

' Initialize a List
NamesList = New List(Of TextBox)({TextBox1, TextBox2, TextBox3...})
' or
NamesList = New List(Of TextBox)
NamesList.AddRange({TextBox1, TextBox2, TextBox3...})

وظيفة عودة لا شيء

Private bars As New List(Of Bars)        ' Declared and created

Public Function BarList() As List(Of Bars)
    bars.Clear
    If someCondition Then
        For n As Integer = 0 to someValue
            bars.Add(GetBar(n))
        Next n
    Else
        Exit Function
    End If

    Return bars
End Function

هذه هي الحالة التي سوف إيد تحذيرك أن " ليس كل المسارات إرجاع قيمة و NullReferenceException قد يؤدي ". يمكنك إلغاء التحذير، عن طريق استبدال Exit Function مع Return Nothing ، ولكن هذا لا يحل المشكلة. أي شيء يحاول استخدام العودة عندما someCondition = False سيؤدي إلى نري:

bList = myFoo.BarList()
For Each b As Bar in bList      ' EXCEPTION
      ...

علاج

استبدال Exit Function في الدالة مع Return bList . إعادة List فارغة ليست هي نفسها كما يعود Nothing . إذا كان هناك احتمال أن كائن عاد يمكن أن يكون Nothing ، اختبار قبل استخدامه:

 bList = myFoo.BarList()
 If bList IsNot Nothing Then...

ضعيفة نفذت محاولة / قبض

محاولة سيئة محاولة / الصيد يمكن أن تخفي حيث المشكلة هي وتؤدي إلى جديدة:

Dim dr As SqlDataReader
Try
    Dim lnk As LinkButton = TryCast(sender, LinkButton)
    Dim gr As GridViewRow = DirectCast(lnk.NamingContainer, GridViewRow)
    Dim eid As String = GridView1.DataKeys(gr.RowIndex).Value.ToString()
    ViewState("username") = eid
    sqlQry = "select FirstName, Surname, DepartmentName, ExtensionName, jobTitle,
             Pager, mailaddress, from employees1 where username='" & eid & "'"
    If connection.State <> ConnectionState.Open Then
        connection.Open()
    End If
    command = New SqlCommand(sqlQry, connection)

    'More code fooing and barring

    dr = command.ExecuteReader()
    If dr.Read() Then
        lblFirstName.Text = Convert.ToString(dr("FirstName"))
        ...
    End If
    mpe.Show()
Catch

Finally
    command.Dispose()
    dr.Close()             ' <-- NRE
    connection.Close()
End Try

هذه هي حالة عدم إنشاء كائن كما هو متوقع، ولكن أيضا يدل على فائدة العداد من Catch فارغة.

هناك فاصلة إضافية في سكل (بعد 'ميلادريس') الذي يؤدي إلى استثناء في .ExecuteReader . بعد Catch لا يفعل شيئا، Finally يحاول تنفيذ تنظيف، ولكن منذ لا يمكنك Close كائن DataReader نول، نتائج العلامة التجارية الجديدة NullReferenceException .

كتلة Catch فارغة هو ملعب الشيطان. وكان هذا أوب محيرة لماذا كان الحصول على نري في كتلة Finally .في حالات أخرى، فارغة Catchقد يؤدي إلى شيء آخر يحدث أبعد من ذلك بكثير المصب أحمق ويسبب لك لقضاء بعض الوقت تبحث في الأشياء الخاطئة في المكان الخطأ لهذه المشكلة. (و"استثناء الصامت" هو موضح أعلاه يوفر قيمة الترفيه نفسها.)

علاج

لا تستخدم كتل حاول / اقبض فارغة - السماح للتحطم التعليمات البرمجية بحيث يمكنك أ) تحديد سبب ب) تحديد مكان وج) تطبيق العلاج السليم. محاولة / لا يقصد كتل اقبض لإخفاء استثناءات من شخص مؤهل بشكل فريد لاصلاحها - المطور.

DBNULL ليست هي نفسها كما لا شيء

For Each row As DataGridViewRow In dgvPlanning.Rows
    If Not IsDBNull(row.Cells(0).Value) Then
        ...

و IsDBNullيتم استخدام الدالة لاختبار ما إذا كان قيمة تساوي System.DBNull: من MSDN:

وتشير قيمة System.DBNull أن كائن يمثل البيانات المفقودة أو غير موجودة. DBNULL ليست هي نفسها كما لا شيء، مما يدل على أن متغير لم يتم تهيئة.

علاج

If row.Cells(0) IsNot Nothing Then ...

كما كان من قبل، يمكنك اختبار للا شيء، ثم لقيمة معينة:

If (row.Cells(0) IsNot Nothing) AndAlso (IsDBNull(row.Cells(0).Value) = False) Then

مثال 2

Dim getFoo = (From f In dbContext.FooBars
               Where f.something = something
               Select f).FirstOrDefault

If Not IsDBNull(getFoo) Then
    If IsDBNull(getFoo.user_id) Then
        txtFirst.Text = getFoo.first_name
    Else
       ...

FirstOrDefaultإرجاع البند الأول أو القيمة الافتراضية، والتي هي Nothingلأنواع المرجعية وأبدا DBNull:

If getFoo IsNot Nothing Then...

ضوابط

Dim chk As CheckBox

chk = CType(Me.Controls(chkName), CheckBox)
If chk.Checked Then
    Return chk
End If

إذا كان CheckBoxمع chkNameلا يمكن العثور عليه (أو موجود في GroupBox)، ثم chkسوف يكون لا شيء، وأن تحاول الرجوع أي ممتلكات سيؤدي إلى استثناء.

علاج

If (chk IsNot Nothing) AndAlso (chk.Checked) Then ...

وداتاغريدفيف

وDGV لديها عدد قليل من المراوغات ينظر دوري:

dgvBooks.DataSource = loan.Books
dgvBooks.Columns("ISBN").Visible = True       ' NullReferenceException
dgvBooks.Columns("Title").DefaultCellStyle.Format = "C"
dgvBooks.Columns("Author").DefaultCellStyle.Format = "C"
dgvBooks.Columns("Price").DefaultCellStyle.Format = "C"

إذا dgvBooksديه AutoGenerateColumns = True، فإنه سيتم إنشاء الأعمدة، ولكن لا اسم لها، حتى يفشل رمز أعلاه عندما يحيل منهم بالاسم.

علاج

تسمية الأعمدة يدويا، أو المرجع من قبل الفهرس:

dgvBooks.Columns(0).Visible = True

مثال 2 - احذر من NewRow

xlWorkSheet = xlWorkBook.Sheets("sheet1")

For i = 0 To myDGV.RowCount - 1
    For j = 0 To myDGV.ColumnCount - 1
        For k As Integer = 1 To myDGV.Columns.Count
            xlWorkSheet.Cells(1, k) = myDGV.Columns(k - 1).HeaderText
            xlWorkSheet.Cells(i + 2, j + 1) = myDGV(j, i).Value.ToString()
        Next
    Next
Next

عندما الخاص بك DataGridViewلديها AllowUserToAddRowsكما True(الافتراضي)، و Cellsفي فارغة / صف جديد في الجزء السفلي وتحتوي على كافة Nothing. معظم محاولات لاستخدام محتويات (على سبيل المثال، ToString) سوف يؤدي إلى NRE.

علاج

استخدام For/Eachحلقة واختبار IsNewRowالخاصية لتحديد ما إذا كان هذا الصف الأخير. هذا وتعمل سواء AllowUserToAddRowsهو صحيح أم لا:

For Each r As DataGridViewRow in myDGV.Rows
    If r.IsNewRow = False Then
         ' ok to use this row

إذا كنت لا تستخدم For nحلقة، تعديل عدد الصفوف أو استخدام Exit Forعند IsNewRowغير صحيح.

My.Settings (StringCollection)

في ظل ظروف معينة، في محاولة لاستخدام عنصر من My.Settingsوهو StringCollectionيمكن أن يؤدي إلى NullReference أول مرة استخدامه. الحل هو نفسه، ولكن ليس واضحا كما. يعتبر:

My.Settings.FooBars.Add("ziggy")         ' foobars is a string collection

منذ VB وإدارة إعدادات بالنسبة لك، فمن المعقول أن نتوقع أن تهيئة المجموعة. سوف، ولكن فقط إذا قمت بإضافة سابقا إدخال الأولي إلى جمع (في محرر الضبط). منذ المجموعة هي (على ما يبدو) تهيئة عند إضافة عنصر، فإنه لا يزال Nothingعند وجود أي عناصر في إعدادات محرر لإضافة.

علاج

تهيئة إعدادات جمع في النموذج Loadمعالج الحدث، إذا / عند الحاجة:

If My.Settings.FooBars Is Nothing Then
    My.Settings.FooBars = New System.Collections.Specialized.StringCollection
End If

عادة، و Settingsسوف جمع تحتاج فقط ليتم تهيئتها أول مرة يتم تشغيل التطبيق. وسيلة انتصاف البديل هو لإضافة القيمة الأولية لجمع الخاصة بك في المشروع -> إعدادات | FooBars ، حفظ المشروع، ثم إزالة قيمة وهمية.

النقاط الرئيسية

ربما كنت قد نسيت Newالمشغل.

أو

شيء توليتم من شأنها أن تؤدي لا تشوبه شائبة للعودة كائن تهيئة إلى التعليمات البرمجية، لا.

لا تتجاهل تحذيرات مترجم (أي وقت مضى) واستخدام Option Strict On(دائما).

MSDN NullReference استثناء




سيناريو آخر هو عندما يلقي جوه لاغية إلى نوع القيمة . على سبيل المثال، رمز أدناه:

    object o = null;
    DateTime d = (DateTime)o;

وسوف يلقي NullReferenceExceptionعلى المدلى بها. ويبدو واضحا تماما في العينة المذكورة أعلاه، ولكن هذا يمكن أن يحدث في أكثر السيناريوهات المعقدة "الربط المتأخر" حيث تم إرجاع الكائن باطل من بعض التعليمات البرمجية التي لا تملك، ويلقي على سبيل المثال الناتجة عن بعض النظام الآلي.

وأحد الأمثلة على ذلك هو هذا جزء بسيط ASP.NET ملزم مع عنصر التقويم:

<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />

هنا، SelectedDateهو في الواقع عقار - من DateTimeنوع - من Calendarالتحكم في نوع ويب، والربط يمكن تماما العودة شيء باطل. سوف ASP.NET مولد الضمني خلق قطعة من التعليمات البرمجية التي سوف يكون معادلا لرمز يلقي أعلاه. وهذا من شأنه رفع NullReferenceExceptionيصعب جدا على الفور، لأنها تقع في ASP.NET إنشاء التعليمات البرمجية التي تجمع بخير ...




وهو ما يعني أن المتغير في السؤال هو أشار في شيء. أنا يمكن أن يولد هذا مثل ذلك:

SqlConnection connection = null;
connection.Open();

وهذا رمي الخطأ لأنه في حين لقد تعريف المتغير " connection"، انها ليست أشار إلى أي شيء. عندما أحاول أن استدعاء الأعضاء " Open"، وليس هناك إشارة لذلك لحل، وأنه سوف يرمي خطأ.

لتجنب هذا الخطأ:

  1. تهيئة دائما الأشياء الخاصة بك قبل أن تحاول أن تفعل أي شيء معهم.
  2. إذا كنت غير متأكد ما إذا كان الكائن باطل، التحقق من ذلك مع object == null.

سوف أداة Resharper JetBrains 'تحديد كل مكان في التعليمات البرمجية التي لديها إمكانية وجود خطأ مرجع فارغة، مما يتيح لك وضع في الاختيار فارغة. هذا الخطأ هو المصدر رقم واحد من البق، IMHO.




وهو ما يعني الشفرة تستخدم متغير مرجع الكائن الذي كان من المقرر أن فارغة (أي أنها لم ترجع مثيل كائن الفعلي).

لمنع الخطأ، يجب اختبار الأجسام التي يمكن أن تكون لاغية لاغية قبل استخدامها.

if (myvar != null)
{
    // Go ahead and use myvar
    myvar.property = ...
}
else
{
    // Whoops! myvar is null and cannot be used without first
    // assigning it to an instance reference
    // Attempting to use myvar here will result in NullReferenceException
}



كن على علم أنه بغض النظر عن السيناريو، والسبب هو نفسه دائما في .NET:

تحاول استخدام متغير إشارة التي تقدر قيمتها Nothing/ null. عندما تكون القيمة Nothing/ nullللمتغير إشارة، وهذا يعني أنها ليست في الواقع عقد إشارة إلى مثيل من أي كائن موجود على الكومة.

اما أبدا تعيين شيء إلى المتغير أبدا إنشاء مثيل من القيمة التي تم تعيينها إلى متغير، أو تعيين متغير يساوي Nothing/ nullيدويا، أو يمكنك استدعاء دالة أن تعيين متغير ل Nothing/ nullبالنسبة لك.




مثال هذا الاستثناء يتم طرح هو: عندما تحاول أن تحقق شيئا، وهذا هو فارغة.

فمثلا:

string testString = null; //Because it doesn't have a value (i.e. it's null; "Length" cannot do what it needs to do)

if (testString.Length == 0) // Throws a nullreferenceexception
{
    //Do something
} 

فإن وقت التشغيل .NET رمي NullReferenceException عند محاولة تنفيذ إجراء على شيء الذي لم مثيل أي رمز أعلاه.

في مقارنة لArgumentNullException والتي عادة ما يلقى كإجراء دفاعي إذا تتوقع طريقة أن ما يجري تمريرها إلى أنها ليست فارغة.

المزيد من المعلومات في C # NullReferenceException وخالية معلمة .




إذا لم تكن قد تهيئة نوع مرجع، وكنت ترغب في تعيين أو قراءة واحدة من خصائصه، وسوف رمي NullReferenceException .

مثال:

Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.

يمكنك ببساطة تجنب هذا عن طريق فحص إذا كان المتغير هو غير فارغة:

Person p = null;
if (p!=null)
{
    p.Name = "Harry"; // Not going to run to this point
}

لنفهم تماما لماذا يتم طرح NullReferenceException، فمن المهم أن نعرف الفرق بين أنواع قيمة و أنواع مرجع .

لذا، إذا كنت تتعامل مع أنواع القيمة ، NullReferenceExceptions يمكن أن لا يحدث. وإن كنت بحاجة للحفاظ على حالة تأهب عند التعامل مع أنواع المراجع !

مرجع فقط أنواع، مثل اسم يقترح، يمكن أن تعقد مراجع أو تشير حرفيا إلى أي شيء (أو "لاغية"). في حين أن أنواع القيمة دائما تحتوي على قيمة.

أنواع المراجع (يجب أن يتم فحص هذه منها):

  • ديناميكي
  • موضوع
  • خيط

أنواع قيمة (يمكنك ببساطة تجاهل هؤلاء الصغار):

  • أنواع رقمية
  • أنواع متكاملة
  • أنواع الفاصلة العائمة
  • عدد عشري
  • منطقي
  • البنيات المعرفة



حالة أخرى حيث NullReferenceExceptionsيمكن أن يحدث هو (غير صحيح) استخدام asالمشغل :

class Book {
    public string Name { get; set; }
}
class Car { }

Car mycar = new Car();
Book mybook = mycar as Book;   // Incompatible conversion --> mybook = null

Console.WriteLine(mybook.Name);   // NullReferenceException

هنا، Bookو Carهي أنواع غير متوافقة. و Carلا يمكن تحويلها / يلقي ل Book. عندما يفشل هذا المدلى بها، و asيعود null. استخدام mybookبعد هذا يسبب NullReferenceException.

بشكل عام، يجب عليك استخدام الجبس أو asعلى النحو التالي:

إذا كنت تتوقع تحويل نوع للنجاح دائما (. أي أنك تعرف ما ينبغي أن يكون الهدف في وقت مبكر)، ثم يجب عليك استخدام يلقي:

ComicBook cb = (ComicBook)specificBook;

إذا كنت غير متأكد من نوع، ولكن تريد محاولة لاستخدامه بمثابة نوع معين، ثم استخدم as:

ComicBook cb = specificBook as ComicBook;
if (cb != null) {
   // ...
}



كنت تستخدم الكائن الذي يحتوي على إشارة قيمة فارغة. حتى انها لإعطاء استثناء فارغة. في المثال قيمة السلسلة فارغة وعند التدقيق طوله، حدث الاستثناء.

مثال:

string value = null;
if (value.Length == 0) // <-- Causes exception
{
    Console.WriteLine(value); // <-- Never reached
}

الخطأ الاستثناء هو:

استثناء غير معالج:

System.NullReferenceException: مرجع كائن لم يتم تعيين إلى مثيل كائن. في Program.Main ()




قدم سيمون مورير هذا المثال :

object o = null;
DateTime d = (DateTime)o;  // NullReferenceException

حيث ل أونبوإكسينغ التحويل (الزهر) من object (أو من إحدى الطبقات System.ValueTypeأو System.Enum، أو من نوع واجهة) إلى نوع قيمة (غير Nullable<>) في حد ذاته يعطي NullReferenceException.

في الاتجاه الآخر، و الملاكمة تحويل من و Nullable<>الذي HasValueيساوي false إلى نوع مرجع، يمكن أن تعطي nullإشارة التي يمكن أن يؤدي بعد ذلك في وقت لاحق ل NullReferenceException. والمثال الكلاسيكي هو:

DateTime? d = null;
var s = d.ToString();  // OK, no exception (no boxing), returns ""
var t = d.GetType();   // Bang! d is boxed, NullReferenceException

أحيانا يحدث الملاكمة بطريقة أخرى. على سبيل المثال مع هذا الأسلوب تمديد غير عام:

public static void MyExtension(this object x)
{
  x.ToString();
}

سوف التعليمة البرمجية التالية يكون إشكاليا:

DateTime? d = null;
d.MyExtension();  // Leads to boxing, NullReferenceException occurs inside the body of the called method, not here.

هذه الحالات تنشأ بسبب القواعد الخاصة يستخدم وقت التشغيل عند الملاكمة Nullable<>الحالات.




في حين ما يسبب NullReferenceExceptions والنهج ل تجنب / إصلاح هذا الاستثناء قد تم تناولها في إجابات أخرى، ما كثير من المبرمجين لم يتعلموا بعد هو كيفية مستقل تصحيح هذه الاستثناءات خلال التنمية.

في Visual Studio هذا هو عادة بفضل سهلة لل البصرية ستوديو المصحح .

أولا، تأكد من أن الخطأ الصحيح سوف يتم القبض - راجع كيف يمكنني السماح كسر على 'System.NullReferenceException' في VS2010؟ ملاحظة 1

ثم إما البدء مع التصحيح (F5) أو إرفاق [المصحح VS] لتشغيل عملية . في بعض الأحيان قد يكون من المفيد استخدام Debugger.Break، مما سيدفع لإطلاق المصحح.

الآن، عندما يتم طرح NullReferenceException (أو غير معالج) المصحح ستتوقف (تذكر القاعدة المبينة أعلاه؟) على الخط الذي حدث الاستثناء. أحيانا الخطأ سوف يكون من السهل على الفور.

على سبيل المثال، في السطر التالي رمز الوحيد الذي يمكن أن يسبب يستثنى من ذلك إذا myStringيقيم لاغية. يمكن التحقق من ذلك من خلال النظر في إطار المراقبة أو تشغيل التعبيرات في الإطار الحالي .

var x = myString.Trim();

في الحالات الأكثر تقدما، مثل التالية، سوف تحتاج إلى استخدام واحدة من التقنيات أعلاه (ووتش أو فوري ويندوز) لتفقد تعابير لتحديد ما إذا str1كانت خالية أو إذا str2كان لاغيا.

var x = str1.Trim() + str2.Trim();

مرة واحدة حيث يتم رمي وقد يقع الاستثناء، انها عادة ما تكون تافهة لسبب الوراء لمعرفة أين كانت قيمة فارغة [صحيح] قدم -

خذ الوقت اللازم لفهم سبب الاستثناء. تفتيش للتعبير فارغة. تفقد التعبيرات السابقة التي كان يمكن أن يؤدي في هذه التعبيرات فارغة. إضافة نقاط التوقف والتنقل خلال البرنامج حسب الاقتضاء. استخدام المصحح.

1 إذا استراحة على الرميات غير عدوانية جدا وتوقف المصحح على NPE في .NET أو مكتبة 3rd الطرف، كسر على المستخدم غير معالج يمكن استخدامها للحد من الاستثناءات القبض عليهم. بالإضافة إلى ذلك، يقدم VS2012 فقط بلدي الرمز الذي أوصى تمكن أيضا.

إذا كان يتم تصحيحه مع مجرد بلدي كود تمكين سلوك مختلف قليلا. مع مجرد رمز بلادي تمكين يتجاهل المصحح فرصة الأول وقت تشغيل اللغة العامة (CLR) الاستثناءات التي القيت خارج من قانون بلدي ولا تمر من خلال قانون بلدي




إضافة حالة عندما يكون اسم فئة لكيان المستخدمة في إطار الكيان نفس اسم الفئة للنموذج ويب ملف التعليمات البرمجية الخلفية.

افترض أن لديك Contact.aspx نموذج ويب الذي هو الاتصال الطبقة codebehind وكان لديك اسم الكيان الاتصال.

ثم البرمجية التالية سوف رمي NullReferenceException عند استدعاء context.SaveChanges ()

Contact contact = new Contact { Name = "Abhinav"};
var context = new DataContext();
context.Contacts.Add(contact);
context.SaveChanges(); // NullReferenceException at this line

من أجل الطبقة DataContext اكتمال

public class DataContext : DbContext 
{
    public DbSet<Contact> Contacts {get; set;}
}

والطبقة كيان الاتصال. أحيانا الطبقات كيان هي فئات جزئية بحيث يمكنك توسيعها في ملفات أخرى أيضا.

public partial class Contact 
{
    public string Name {get; set;}
}

يحدث الخطأ عند كل من كيان والطبقة codebehind هم في نفس مساحة الاسم. لحل هذه المشكلة، إعادة تسمية الطبقة كيان أو فئة codebehind لContact.aspx.

السبب ما زلت غير متأكد من السبب. ولكن كلما أي من الطبقة كيان ستمتد System.Web.UI.Page يحدث هذا الخطأ.

للنقاش إلقاء نظرة على NullReferenceException في DbContext.saveChanges ()




حالة عامة أخرى حيث يمكن للمرء أن تلقي هذا الاستثناء تتضمن فصول ساخرة خلال اختبار وحدة. بغض النظر عن الإطار ساخرا المستخدمة، يجب عليك التأكد من أن جميع المستويات المناسبة من التسلسل الهرمي فئة وسخر بشكل صحيح. على وجه الخصوص، كل خصائص HttpContextيتم الرجوع إليها التي كتبها يجب أن سخر رمز تحت الاختبار.

انظر " NullReferenceException ألقيت عند اختبار مخصص AuthorizationAttribute " لسبيل المثال مطول بعض الشيء.




لدي وجهة نظر مختلفة للإجابة على هذا. هذا النوع من الإجابات "ماذا يمكنني أن أفعل لتجنب ذلك؟ "

عند العمل عبر طبقات مختلفة ، على سبيل المثال في تطبيق MVC، وحدة تحكم يحتاج خدمات للاتصال العمليات التجارية. في مثل هذه السيناريوهات التبعية حقن الحاويات يمكن استخدامها لتهيئة الخدمات لتجنب NullReferenceException . وهذا يعني أنك لا داعي للقلق بشأن التحقق من وجود باطل ومجرد دعوة الخدمات من وحدة تحكم كما لو أنها سوف دائما متوفرة (وتهيئة) إما عن المفردة أو النموذج.

public class MyController
{
    private ServiceA serviceA;
    private ServiceB serviceB;

    public MyController(ServiceA serviceA, ServiceB serviceB)
    {
        this.serviceA = serviceA;
        this.serviceB = serviceB;
    }

    public void MyMethod()
    {
        // We don't need to check null because the dependency injection container 
        // injects it, provided you took care of bootstrapping it.
        var someObject = serviceA.DoThis();
    }
}



بشأن مسألة "ماذا علي أن أفعل حيال ذلك" ، يمكن أن يكون هناك العديد من الإجابات.

وسيلة أكثر "رسمية" لمنع مثل هذه الظروف خطأ مع تطوير وتطبيق تصميم بالعقود في التعليمات البرمجية. هذا يعني أنك تحتاج إلى تعيين الدرجة الثوابت ، و / أو حتى وظيفة / طريقة شروط مسبقة و postconditions على النظام الخاص بك، في حين النامية.

باختصار، الثوابت الطبقة ضمان أنه سيكون هناك بعض القيود في صفك التي لن تحصل على انتهكت في الاستخدام العادي (وبالتالي، فإن الطبقة سوف لا يحصل في حالة غير متناسقة). شروط مسبقة يعني أن البيانات الواردة كمدخل إلى وظيفة / طريقة يجب أن تتبع مجموعة بعض القيود و لم تنتهك لهم، و postconditions يعني أن الانتاج وظيفة / طريقة يجب أن تتبع القيود مجموعة ثانية من دون انتهاكها من أي وقت مضى. يجب أن شروط العقد لم يتم انتهاك أثناء تنفيذ برنامج خالية من الشوائب، وبالتالي تصميم بموجب عقد يتم التحقق عمليا في وضع التصحيح، في حين يجري تعطيل في الإصدارات ، لتعظيم أداء النظام المتقدمة.

بهذه الطريقة، يمكنك تجنب NullReferenceExceptionالحالات التي هي نتائج مخالفة للقيود الموضوعة. على سبيل المثال، إذا كنت تستخدم خاصية الكائن Xفي فئة وبعد ذلك محاولة استدعاء واحد من أساليب و Xيحتوي على قيمة فارغة، فإن هذا سيؤدي إلى NullReferenceException:

public X { get; set; }

public void InvokeX()
{
    X.DoSomething(); // if X value is null, you will get a NullReferenceException
}

ولكن إذا قمت بتعيين "الملكية X يجب أبدا أن يكون قيمة فارغة" كطريقة مسبق، ثم يمكنك منع السيناريو الموضحة من قبل:

//Using code contracts:
[ContractInvariantMethod]
protected void ObjectInvariant () 
{
    Contract.Invariant ( X != null );
    //...
}

لهذا السبب، قانون العقود وجود مشروع لتطبيقات .NET.

بدلا من ذلك، تصميم بالعقود يمكن تطبيقها باستخدام التأكيدات .

UPDATE: ومن الجدير بالذكر أن مصطلح التي صيغت من قبل برتراند ماير في اتصال مع تصميمه من لغة البرمجة ايفل .




و NullReferenceExceptionيتم طرح عندما نحاول الوصول إلى خصائص كائن خالية أو عندما تصبح قيمة سلسلة فارغة ونحن نحاول الوصول إلى طرق السلسلة.

فمثلا:

  1. عندما طريقة سلسلة من سلسلة فارغة الوصول:

    string str = string.Empty;
    str.ToLower(); // throw null reference exception
  2. عندما خاصية لاغية وجوه الوصول إليها:

    Public Class Person {
        public string Name { get; set; }
    }
    Person objPerson;
    objPerson.Name  /// throw Null refernce Exception 



TL، DR: حاول استخدام Html.Partialبدلا منRenderpage

كنت الحصول Object reference not set to an instance of an objectعندما حاولت أن تجعل طريقة عرض في طريقة عرض عن طريق إرساله النموذجي، مثل هذا:

@{
    MyEntity M = new MyEntity();
}
@RenderPage("_MyOtherView.cshtml", M); // error in _MyOtherView, the Model was Null

أظهرت التصحيح كان النموذج لاغية داخل MyOtherView. حتى أنا تغييره إلى:

@{
    MyEntity M = new MyEntity();
}
@Html.Partial("_MyOtherView.cshtml", M);

وأنه يعمل.

وعلاوة على ذلك، والسبب لم يكن لدي Html.Partialكان في البداية بسبب Visual Studio أحيانا يلقي خطوط الخطأ تبحث متعرج تحت Html.Partialلو كان داخل شيدت بشكل مختلف foreachحلقة، على الرغم من أنها ليست حقا خطأ:

@inherits System.Web.Mvc.WebViewPage
@{
    ViewBag.Title = "Entity Index";
    List<MyEntity> MyEntities = new List<MyEntity>();
    MyEntities.Add(new MyEntity());
    MyEntities.Add(new MyEntity());
    MyEntities.Add(new MyEntity());
}
<div>
    @{
        foreach(var M in MyEntities)
        {
            // Squiggly lines below. Hovering says: cannot convert method group 'partial' to non-delegate type Object, did you intend to envoke the Method?
            @Html.Partial("MyOtherView.cshtml");
        }
    }
</div>

لكني لم اكن قادرا على تشغيل التطبيق مع عدم وجود مشاكل مع هذا "الخطأ". وكنت قادرا على التخلص من الخطأ عن طريق تغيير هيكل foreachحلقة لتبدو مثل هذا:

@foreach(var M in MyEntities){
    ...
}

على الرغم من أن لدي شعور انه بسبب Visual Studio تم قراءة خاطئة للالوات والأقواس.




ماذا يمكنك أن تفعل بهذا الشأن؟

هناك الكثير من الإجابات جيدة هنا شرح ما هي مرجع فارغة وكيفية تصحيح ذلك. ولكن هناك القليل جدا حول كيفية منع هذه المسألة أو على الأقل جعلها أسهل للقبض.

تحقق الحجج

على سبيل المثال، يمكن أن طرق التحقق من الحجج المختلفة لمعرفة ما إذا كانت لاغية والإلقاء ArgumentNullException، استثناء خلق الواضح لهذا الغرض المحدد.

المنشئ ل ArgumentNullExceptionحتى يأخذ اسم المعلمة ورسالة كوسائط لذلك يمكن أن أقول لكم المطور بالضبط ما هي المشكلة.

public void DoSomething(MyObject obj) {
    if(obj == null) 
    {
        throw new ArgumentNullException("obj", "Need a reference to obj.");
    }
}

استخدام أدوات

هناك أيضا العديد من المكتبات التي يمكن أن تساعد. "Resharper" على سبيل المثال يمكن أن توفر لك مع وجود تحذيرات أثناء كتابة التعليمات البرمجية، خاصة إذا كنت تستخدم سمة من: NotNullAttribute

هناك "عقود كود مايكروسوفت" حيث يمكنك استخدام جملة مثل Contract.Requires(obj != null)التي تعطيك وقت التشغيل وتجميع التحقق: إدخال كود العقود .

وهناك أيضا "PostSharp" التي تسمح لك لمجرد استخدام سمات مثل هذا:

public void DoSometing([NotNull] obj)

من يفعل ذلك، وجعل PostSharp جزءا من عملية الإنشاء الخاصة بك objوسيتم فحص لاغية في وقت التشغيل. انظر: PostSharp الاختيار لاغيا

سهل كود الحل

أو يمكنك دائما رمز النهج الخاص بك باستخدام القانون القديم عادي. على سبيل المثال هنا هو البنية التي يمكنك استخدامها لالتقاط إشارات فارغة. انها على غرار نفس المفهوم Nullable<T>:

[System.Diagnostics.DebuggerNonUserCode]
public struct NotNull<T> where T: class
{
    private T _value;

    public T Value
    {
        get
        {
            if (_value == null)
            {
                throw new Exception("null value not allowed");
            }

            return _value;
        }
        set
        {
            if (value == null)
            {
                throw new Exception("null value not allowed.");
            }

            _value = value;
        }
    }

    public static implicit operator T(NotNull<T> notNullValue)
    {
        return notNullValue.Value;
    }

    public static implicit operator NotNull<T>(T value)
    {
        return new NotNull<T> { Value = value };
    }
}

يمكنك استخدام تشبه الى حد بعيد بنفس الطريقة التي ستستخدم Nullable<T>، باستثناء بهدف تحقيق العكس تماما - عدم السماح null. وهنا بعض الأمثلة:

NotNull<Person> person = null; // throws exception
NotNull<Person> person = new Person(); // OK
NotNull<Person> person = GetPerson(); // throws exception if GetPerson() returns null

NotNull<T>ويلقي ضمنا من وإلى Tذلك يمكنك استخدامه في أي مكان تقريبا كنت في حاجة إليها. على سبيل المثال، يمكنك تمرير Personالكائن إلى الأسلوب الذي يأخذ NotNull<Person>:

Person person = new Person { Name = "John" };
WriteName(person);

public static void WriteName(NotNull<Person> person)
{
    Console.WriteLine(person.Value.Name);
}

كما ترون أعلاه كما هو الحال مع قيم الفارغة كنت الوصول إلى القيمة الأساسية من خلال Valueملكية. بدلا من ذلك، يمكنك استخدام يلقي صريح أو ضمني، يمكنك مشاهدة مثال مع قيمة الإرجاع أدناه:

Person person = GetPerson();

public static NotNull<Person> GetPerson()
{
    return new Person { Name = "John" };
}

أو يمكنك حتى استخدامها عند إرجاع الأسلوب فقط T(في هذه الحالة Person) عن طريق القيام المدلى بها. على سبيل المثال، التعليمة البرمجية التالية أود فقط رمز أعلاه:

Person person = (NotNull<Person>)GetPerson();

public static Person GetPerson()
{
    return new Person { Name = "John" };
}

تتحد مع التمديد

الجمع NotNull<T>مع أسلوب الإرشاد ويمكنك تغطية المزيد من الحالات. هنا هو مثال على ما طريقة تمديد يمكن أن تبدو مثل:

[System.Diagnostics.DebuggerNonUserCode]
public static class NotNullExtension
{
    public static T NotNull<T>(this T @this) where T: class
    {
        if (@this == null)
        {
            throw new Exception("null value not allowed");
        }

        return @this;
    }
}

وهنا مثال على الكيفية التي يمكن استخدامها:

var person = GetPerson().NotNull();

جيثب

للرجوع اليها أدليت به رمز أعلاه متوفرة في جيثب، يمكنك العثور عليها على العنوان التالي:

https://github.com/luisperezphd/NotNull

اللغة ذات الصلة ميزة

C # 6.0 قدم "المشغلين لاغية المشروط" الذي يساعد مع هذا قليلا. مع هذه الميزة، يمكنك الرجوع الأشياء المتداخلة وإذا كان أي واحد منهم هو nullيعود التعبير كلها null.

وهذا يقلل من عدد الشيكات فارغة ما عليك القيام به في بعض الحالات. بناء الجملة هو وضع علامة استفهام أمام كل نقطة. خذ البرمجية التالية على سبيل المثال:

var address = country?.State?.County?.City;

تخيل أن countryهو كائن من نوع Countryالذي يحتوي على خاصية تسمى Stateوهلم جرا. إذا country، State، County، أو Cityغير nullذلك address will beباطل . Therefore you only have to check whetherعنوان isnull`.

إنها ميزة كبيرة، لكنه يتيح لك معلومات أقل. أنها لا تجعل من الواضح أي من 4 لاغيا.

المدمج في مثل قيم الفارغة؟

C # لديه الاختزال لطيفة Nullable<T>، يمكنك تقديم شيء قيم الفارغة عن طريق وضع علامة استفهام بعد نوع مثل ذلكint? .

وسيكون لطيفا لو C # زيارتها شيء مثل NotNull<T>البنية أعلاه وزيارتها اختزال مماثل، وربما تعجب حتى أنك يمكن أن أكتب شيئا مثل (!): public void WriteName(Person! person).




خط خطأ "كائن مرجع لم يتم تعيين إلى مثيل كائن." تنص على أن لديك لم يتم تعيين الكائن سبيل المثال إلى مرجع كائن وما زال يمكنك الوصول إلى الخواص / الأساليب من هذا الكائن.

على سبيل المثال: لنفترض لديك فئة تسمى myClass وأنه يحتوي على prop1 خاصية واحدة.

public Class myClass
{
   public int prop1 {get;set;}
}

الآن يمكنك الوصول إلى هذه prop1 في بعض فئة أخرى تماما مثل أدناه:

public class Demo
{
     public void testMethod()
     {
        myClass ref = null;
        ref.prop1 = 1;  //This line throws error
     }
}

سطر أعلاه رميات الخطأ لأن يتم التصريح إشارة من myClass الفئة ولكن لا مثيل أو لا يتم تعيين مثيل كائن إلى referecne من تلك الفئة.

لإصلاح هذه لديك لإنشاء مثيل (تعيين الكائن إلى إشارة من تلك الفئة).

public class Demo
{
     public void testMethod()
     {
        myClass ref = null;
        ref = new myClass();
        ref.prop1 = 1;  
     }
}



ومن المثير للاهتمام، فإن أيا من الأجوبة على هذه الصفحة تذكر الحالات حافة اثنين، آمل أن لا أحد العقول إذا أضيف لهم:

حافة حالة رقم 1: الوصول المتزامن إلى قاموس

القواميس العامة في. NET ليست ذات ألوان وأنها في بعض الأحيان قد رمي NullReferenceأو حتى (أكثر تواترا) و KeyNotFoundExceptionعند محاولة الوصول إلى المفتاح من اثنين من المواضيع المتزامنة. والاستثناء الوحيد هو مضلل جدا في هذه الحالة.

حافة حالة رقم 2: كود غير آمنة

إذا كان NullReferenceExceptionيتم طرح بواسطة unsafeالتعليمات البرمجية، قد نظر في متغيرات المؤشر، والتحقق منها ل IntPtr.Zeroأو شيء من هذا. وهو نفس الشيء ( "لاغية، باستثناء نقطة")، ولكن في التعليمات البرمجية غير آمنة، وغالبا ما يلقي المتغيرات إلى القيمة أنواع / المصفوفات، وما إلى ذلك، وكنت فرقعة رأسك بالحائط، ويتساءل كيف يمكن لنوع قيمة يمكن أن يلقي هذا استثناء.

(وهناك سبب آخر لعدم استخدام كود غير آمنة إلا إذا كنت في حاجة إليها، بالمناسبة)




يحدث NullReferenceException أو مرجع كائن لم يتم تعيين إلى مثيل كائن عندما لا يتم إنشاء مثيل كائن من الفئة التي تحاول استخدامها. فمثلا:

نفترض أن لديك فئة المسمى الطلاب.

public class Student
{
    private string FirstName;
    private string LastName;
    public string GetFullName()
    {
        return FirstName + LastName;
    }
}

الآن، والنظر في فئة أخرى حيث تحاول استرداد الاسم الكامل للطالب.

public class StudentInfo
{      
    public string GetStudentName()
    {
        Student s;
        string fullname = s.GetFullName();
        return fullname;
    }        
}

كما رأينا في رمز أعلاه، البيان طالب الصورة - يعلن فقط المتغير من نوع الطلاب، لاحظ أن الطبقة الطلاب لا مثيل عند هذه النقطة. وبالتالي، عندما بيان s.GetFullName () يعدم، فإنه سوف يرمي NullReferenceException.




حسنا، بعبارات بسيطة:

تحاول الوصول إلى الكائن الذي لم يتم إنشاء أو حاليا لا في الذاكرة.

فكيف لمعالجة هذه:

  1. التصحيح والسماح للكسر المصحح ... وسوف يستغرق لك مباشرة إلى المتغير الذي يتم تقسيم ... والآن مهمتك هي لمجرد تحديد هذا .. باستخدام جديدة الكلمة في المكان المناسب.

  2. إذا كان سبب ذلك على بعض بيانات الأوامر لأن الكائن غير موجود ثم كل ما عليك القيام به هو القيام فحص لاغية والتعامل معها:

    if (i == null) {
        // Handle this
    }
  3. أصعب واحد .. إذا كان GC جمع الكائن بالفعل ... يحدث هذا عادة إذا كنت تحاول العثور على كائن باستخدام السلاسل ... وهذا هو، في العثور عليه من قبل اسم الكائن ثم قد يحدث أن قد وGC بالفعل تنظيفه ... هذا من الصعب العثور على وستصبح تماما مشكلة ... وأفضل طريقة لمعالجة هذه هي القيام شيكات فارغة أينما اللازمة خلال عملية التنمية. هذا سيوفر لك الكثير من الوقت.

من خلال إيجاد بالاسم أعني بعض إطار تسمح لك لFIndObjects باستخدام السلاسل ورمز قد تبدو هذه: FindObject ( "ObjectName")؛




إذا أخذنا في الاعتبار الحالات الشائعة حيث هذا الاستثناء يمكن طرح، الوصول إلى خصائص WITHING الكائن في الأعلى.

مثلا:

string postalcode=Customer.Address.PostalCode; 
//if customer or address is null , this will through exeption

هنا، إذا كان عنوان باطل، ثم سوف تحصل على NullReferenceException.

لذا، كممارسة علينا أن نستخدم دائما الاختيار لاغيا، قبل الوصول إلى خصائص في مثل هذه الكائنات (وخاصة في عامة)

string postalcode=Customer?.Address?.PostalCode;
//if customer or address is null , this will return null, without through a exception



إذا واحد هو الحصول على هذه الرسالة خلال توفير أو جمع بناء، مجرد إغلاق كافة الملفات ثم قم بفتح أي ملف لتجميع وحفظ.

بالنسبة لي كان السبب أن الأول كان إعادة تسمية الملف وكان الملف القديم لا تزال مفتوحة.




فهذا يعني أنك تحاول التلاعب شيء الذي له مرجعية ولكن لم يتم تهيئة بعد
أول شيء نفعله هنا هو مراجعة كل حالة من الحالات التي تم إنشاؤها.

استخدام نقاط التوقف، والساعات، وفحص القيم varibale الخاص بك.
اتبع تتبع مكدس والبحث عن الصف الدقيق والعمود الذي خلق المشكلة




استخدام أساليب وعضو كائن عليك أولا أن إنشاء هذا الكائن. إذا لم يكن لإنشائه (المتغير الذي يجب عقد لم يتم تهيئة الكائن)، ولكن محاولة استخدامها في الطرق أو المتغيرات التي ستحصل على هذا الخطأ.

في وقت ما كنت قد نسيت فقط أن تفعل التهيئة.

تعديل: الجديد لا يمكن أن يعود لاغية، ولكن استثناء النار عندما فشلت. منذ فترة طويلة كان الحال في بعض اللغات، ولكن ليس أكثر من ذلك. بفضلJohn سوندرز لافتا أنه من أصل.




حرفيا أسهل طريقة لإصلاح NullReferenceExeption اثنين من الطرق. إذا كان لديك GameObject على سبيل المثال مع برنامج نصي المرفقة ومتغير اسمه م ع (جسم جاسئ) هذا المتغير سوف تبدأ لاغية عند بدء تشغيل اللعبة.
هذا هو السبب في أنك تحصل على NullReferenceExeption لأن الكمبيوتر ليس لديها بيانات المخزنة في هذا المتغير.

سأكون باستخدام متغير جسم جاسئ كمثال على ذلك.
ويمكننا أن نضيف البيانات بسهولة حقا فعليا في عدد قليل من الطرق:

  1. إضافة جسم جاسئ وجوه الخاص بك مع AddComponent> الفيزياء> جسم جاسئ
    ثم انتقل إلى السيناريو الخاص بك واكتب rb = GetComponent<Rigidbody>();
    هذا سطر من التعليمات البرمجية يعمل بشكل أفضل في ظل قيادتكم Start()أو Awake()وظائف.
  2. يمكنك إضافة عنصر برمجيا وتعيين المتغير في نفس الوقت مع سطر واحد من التعليمات البرمجية: rb = AddComponent<RigidBody>();

المزيد ملاحظات: إذا كنت تريد الوحدة لإضافة عنصر وجوه الخاص بك وكنت قد نسيت لإضافة واحدة، يمكنك كتابة [RequireComponent(typeof(RigidBody))]فوق تعريف فئة الخاص بك (المكان المخصص أدناه كل من usings الخاص بك).
استمتاع ويسخر الألعاب!




أنواع المراجع الافتراضية إلى فارغة للإشارة إلى أنها ليست الرجوع أي كائن. وبالتالي، إذا حاولت والوصول إلى الكائن الذي يتم الرجوع إليها، وهناك ليست واحدة، سوف تحصل على NullReferenceException .

للمثال:

SqlConnection connection = null;
connection.Open();

عند تشغيل هذا الرمز، سوف تحصل:

System.NullReferenceException: Object reference not set to an instance of an object.

يمكنك تجنب هذا الخطأ عن طريق الترميز مثل هذا:

if (connection != null){
    connection.Open();
}

ملاحظة: من أجل تجنب هذا الخطأ يجب تهيئة دائما الأشياء الخاصة بك قبل أن تحاول أن تفعل أي شيء معهم.




وهذا هو الأساس هو استثناء مرجع فارغة . كما مايكروسوفت states-

يتم طرح استثناء NullReferenceException عند محاولة الوصول إلى عضو من نوع قيمتها لاغيا.

ماذا يعني ذالك؟

وهذا يعني إذا أي عضو الذي لا يحمل أي قيمة، ونحن جعل ذلك العضو لأداء مهمة معينة ثم سيقوم النظام بلا شك إرم رسالة وsay-

"يا الانتظار، هذا العضو ليس لديه القيم بحيث أنه لا يمكن تنفيذ المهمة التي كنت تسليم أكثر من ذلك."

يقول استثناء نفسها أن شيئا ما يجري المشار لكن الذي لم يتم تعيين القيمة. ولذلك فإن هذا يدل على أنه يحدث فقط أثناء استخدام أنواع إشارة إلى أنواع القيمة غير قابلة للقيم الفارغة.

لن يحدث NullReferenceException إذا أردنا استخدام أعضاء نوع القيمة.

class Program
{
    static void Main(string[] args)
    {
        string str = null;
        Console.WriteLine(str.Length);
        Console.ReadLine();
    }
}

يظهر رمز أعلاه سلسلة بسيطة الذي تم تعيينه مع فارغة القيمة.

الآن، عندما أحاول طباعة طول السلسلة شارع ، أنا لا تحصل على استثناء غير معالج من نوع 'System.NullReferenceException' حدث رسالة لأن العضو شارع يشير إلى فارغة ولا يمكن أن يكون هناك أي طول فارغة.

" NullReferenceException يحدث" أيضا عندما ننسى إنشاء مثيل نوع مرجع.

لنفترض أن لدي أسلوب فئة وعضو فيها. أنا لم مثيل صفي لكن اسمه فقط صفي. الآن إذا حاولت استخدام الأسلوب، فإن المترجم رمي خطأ أو إصدار تحذير (اعتمادا على المترجم).

class Program
{
    static void Main(string[] args)
    {
        MyClass1 obj;
        obj.foo();  //Use of unassigned local variable 'obj'
    }
}

public class MyClass1
{
    internal void foo()
    {
        Console.WriteLine("hello from foo");

    }
}

مترجم لرمز أعلاه يثير خطأ متغير الكائنات هو غير معين مما يعني أن المتغير لديه القيم الخالية أو لا شيء. مترجم لرمز أعلاه يثير خطأ متغير الكائنات هو غير معين مما يعني أن المتغير لديه القيم الخالية أو لا شيء.

ماذا يحدث؟

  • ينشأ NullReferenceException المقرر ان خطأنا لعدم التحقق قيمة الكائن. نحن غالبا ما تترك القيم الكائن لم يتم التحقق منه في تطوير التعليمات البرمجية.

  • فهي تنشأ أيضا عندما ننسى لإنشاء كائنات لدينا. باستخدام أساليب وخصائص مجموعات الخ والتي يمكن العودة أو تعيين قيم فارغة ويمكن أيضا أن يكون سبب هذا الاستثناء.

وكيف يمكن تجنبها؟

هناك طرق وأساليب مختلفة لتجنب هذا الاستثناء الشهير:

  1. فحص صريح: يجب أن نتمسك بها إلى تقليد للتحقق من الأشياء، وخصائص وأساليب المصفوفات، والمجموعات سواء كانت فارغة. ويمكن تطبيق هذا ببساطة عن طريق استخدام العبارات الشرطية مثل إذا، إلا إذا بين آخر الخ

  2. معالجة الاستثناء: واحدة من الطرق الهامة لإدارة هذا الاستثناء. استخدام بسيطة كتل محاولة تجميع مياه الأمطار أخيرا يمكننا السيطرة على هذا الاستثناء، وكذلك الحفاظ على سجل منه. هذا يمكن أن يكون مفيدا للغاية عندما التطبيق الخاص بك في مرحلة الإنتاج.

  3. مشغلي فارغة: يمكن أيضا المشغل لاغية طريقة جع ومشغلي الشرطية فارغة استخدامها في متناول اليدين في حين يحدد القيم إلى الأشياء، والمتغيرات والممتلكات والحقول.

  4. مصحح: بالنسبة للمطورين، لدينا سلاح كبير من التصحيح معنا. اذا كانت لديك نواجهها NullReferenceException خلال مواجهة التطور يمكننا استخدام المصحح للوصول الى مصدر الاستثناء.

  5. المدمج في الأسلوب: أساليب النظام مثل GetValueOrDefault ()، IsNullOrWhiteSpace () وIsNullorEmpty () شيكات بلا قيم وتعيين القيمة الافتراضية إذا كان هناك قيمة فارغة.

هناك العديد من الإجابات جيدة هنا بالفعل. يمكنك أيضا التحقق من وصف أكثر تفصيلا مع أمثلة على بلدي بلوق .

آمل أن يساعد هذا أيضا!