0 Câu hỏi: Tại sao tôi nhận được tham chiếu Đối tượng không được đặt thành phiên bản của lỗi đối tượng? [bản sao]

câu hỏi được tạo ra tại Wed, May 8, 2019 12:00 AM

Tôi có một số mã và khi nó thực thi, nó sẽ ném NullReferenceException, nói:

  

Tham chiếu đối tượng không được đặt thành phiên bản của đối tượng.

Điều này có nghĩa là gì và tôi có thể làm gì để khắc phục lỗi này?

    
1877
  1. Trình trợ giúp ngoại lệ trong VS 2017 sẽ hữu ích hơn trong việc chẩn đoán nguyên nhân của ngoại lệ này - blog.msdn.microsoft.com/visualstudio/2016/11/11/trong Trình trợ giúp ngoại lệ mới .
    2016-12-29 09: 06: 19Z
  2. Các khách truy cập trong tương lai, câu trả lời cho câu hỏi này cũng áp dụng tương tự cho ArgumentNullException . Nếu câu hỏi của bạn đã bị đóng như là một bản sao của câu hỏi này và bạn đang gặp ANE, vui lòng làm theo hướng dẫn trong câu trả lời để gỡ lỗi và khắc phục sự cố của bạn.
    2017-10-13 17: 56: 23Z
  3. @ sẽ ANE chỉ xảy ra nếu null được truyền dưới dạng tham số. Bạn có thể đưa ra một ví dụ nếu câu hỏi ANE đóng như một bản sao của câu hỏi này không?
    2017-10-14 21: 44: 46Z
  4. Nó xuất hiện trên Meta, nhưng tôi phải đi đào liên kết. Nhưng theo nhận xét đó, ANE chỉ đơn giản là một NRE nhưng có ai đó đã thêm một kiểm tra phòng ngừa và ít nhất bạn biết chính xác null là gì (tên đối số được cung cấp), do đó, việc chẩn đoán dễ dàng hơn một chút so với NRE. /div>
    2017-10-16 12: 53: 02Z
    30 Câu trả lời                              30                         
    Nguyên nhân là gì?

    Dòng dưới

    Bạn đang cố gắng sử dụng một cái gì đó là null (hoặc Nothing trong VB.NET). Điều này có nghĩa là bạn đặt nó thành null hoặc bạn không bao giờ đặt nó thành bất cứ điều gì cả.

    Giống như mọi thứ khác, null được thông qua. Nếu là null trong phương thức "A", thì đó có thể là phương thức "B" đã truyền một phương thức null cho "A".

    null có thể có các ý nghĩa khác nhau:

    1. Các biến đối tượng chưa được khởi tạo và do đó trỏ đến không có gì. Trong trường hợp này, nếu bạn truy cập các thuộc tính hoặc phương thức của các đối tượng đó, nó sẽ gây ra NullReferenceException.
    2. Nhà phát triển đang sử dụng null để chỉ ra rằng không có giá trị có ý nghĩa. Lưu ý rằng C # có khái niệm về kiểu dữ liệu nullable cho các biến (như bảng cơ sở dữ liệu có thể có các trường không thể) đối với họ để chỉ ra rằng không có giá trị nào được lưu trữ trong đó, ví dụ null trong đó dấu hỏi cho biết nó được phép lưu trữ null trong biến int? a = null;. Bạn có thể kiểm tra xem với biến số a hay với 0600350991111010 để truy cập giá trị qua if (a.HasValue) {...} một cách rõ ràng hoặc chỉ như bình thường qua if (a==null) {...}.
      Lưu ý khi truy cập nó qua 060035099111100101350 tức là nếu bạn có một biến không có giá trị khác a thì bạn nên thực hiện các bài tập như a.Value hoặc ngắn hơn a.

    Phần còn lại của bài viết này đi sâu vào chi tiết hơn và chỉ ra những lỗi mà nhiều lập trình viên thường mắc phải có thể dẫn đến a.Value.

    Cụ thể hơn

    Thời gian chạy ném InvalidOperationException luôn có nghĩa tương tự: bạn đang cố sử dụng một tham chiếu và tham chiếu không được khởi tạo (hoặc nó được khởi tạo một lần , nhưng là không còn được khởi tạo).

    Điều này có nghĩa là tham chiếu là NullReferenceException và bạn không thể truy cập các thành viên (chẳng hạn nhưnhư các phương thức) thông qua một tham chiếu a. Trường hợp đơn giản nhất:

    null

    Điều này sẽ ném int b; ở dòng thứ hai vì bạn không thể gọi phương thức cá thể if (a.HasValue) { b = a.Value; } trên tham chiếu if (a != null) { b = a; } trỏ đến NullReferenceException.

    Gỡ lỗi

    Làm thế nào để bạn tìm thấy nguồn của NullReferenceException? Ngoài việc xem xét chính ngoại lệ, sẽ được ném chính xác tại vị trí xảy ra, các quy tắc gỡ lỗi chung trong Visual Studio được áp dụng: đặt các điểm dừng chiến lược và kiểm tra các biến của bạn , bằng cách di chuột qua tên của chúng, mở cửa sổ Xem nhanh (Quick) hoặc sử dụng các bảng gỡ lỗi khác nhau như Locals và Autos.

    Nếu bạn muốn tìm nơi tham chiếu được đặt hoặc không được đặt, hãy nhấp chuột phải vào tên của nó và chọn "Tìm tất cả tài liệu tham khảo". Sau đó, bạn có thể đặt một điểm dừng ở mọi vị trí tìm thấy và chạy chương trình của bạn với trình gỡ lỗi được đính kèm. Mỗi khi trình gỡ lỗi phá vỡ điểm dừng như vậy, bạn cần xác định xem bạn có mong muốn tham chiếu là không null hay không, kiểm tra biến và xác minh rằng nó trỏ đến một thể hiện khi bạn mong đợi nó.

    Bằng cách theo dòng chảy chương trình theo cách này, bạn có thể tìm thấy vị trí mà trường hợp không nên rỗng và tại sao nó không được đặt đúng.

    Ví dụ

    Một số tình huống phổ biến có thể ném ngoại lệ:

    Chung

    null

    Nếu ref1 hoặc ref2 hoặc ref3 là null, thì bạn sẽ nhận được null. Nếu bạn muốn giải quyết vấn đề, hãy tìm ra cái nào là null bằng cách viết lại biểu thức thành tương đương đơn giản hơn:

    string foo = null;
    foo.ToUpper();
    

    Cụ thể, trong NullReferenceException, ToUpper() có thể là null hoặc tài sản string có thể là null hoặc tài sản null có thể là null.

    Gián tiếp

    NullReferenceException

    Nếu bạn muốn tránh tham chiếu null (Person) con, bạn có thể khởi tạo nó trong hàm tạo của đối tượng cha mẹ (Sách).

    Công cụ khởi tạo đối tượng lồng nhau

    Áp dụng tương tự cho các trình khởi tạo đối tượng lồng nhau:

    ref1.ref2.ref3.member
    

    Điều này dịch thành

    NullReferenceException .

    Công cụ khởi tạo bộ sưu tập lồng nhau

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

    Công cụ khởi tạo bộ sưu tập lồng nhau hoạt động giống nhau:

    HttpContext.Current.User.Identity.Name

    Điều này dịch thành

    HttpContext.Current

    User chỉ tạo một phiên bản Identity, nhưng bộ sưu tập

    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.
        }
    }
    
    vẫn là
    Book b1 = new Book { Author = { Age = 45 } };
    
    . Cú pháp khởi tạo bộ sưu tập không tạo ra bộ sưu tập đối với
    Book b1 = new Book();
    b1.Author.Age = 45;
    
    , nó chỉ chuyển thành các câu lệnh new.

    Mảng

    Book

    Các phần tử mảng

    Person

    Mảng răng cưa

    Author

    Bộ sưu tập /Danh sách /Từ điển

    null

    Biến phạm vi (gián tiếp /hoãn)

    public class Person {
        public ICollection<Book> Books { get; set; }
    }
    public class Book {
        public string Title { get; set; }
    }
    

    Sự kiện

    Person p1 = new Person {
        Books = {
            new Book { Title = "Title1" },
            new Book { Title = "Title2" },
        }
    };
    

    Các quy ước đặt tên xấu:

    Nếu bạn đặt tên các trường khác với người địa phương, bạn có thể nhận ra rằng bạn chưa bao giờ khởi tạo trường.

    Person p1 = new Person();
    p1.Books.Add(new Book { Title = "Title1" });
    p1.Books.Add(new Book { Title = "Title2" });
    

    Điều này có thể được giải quyết bằng cách tuân theo quy ước đối với các trường tiền tố có dấu gạch dưới:

    new Person

    Vòng đời trang ASP.NET:

    Person

    Giá trị phiên ASP.NET

    Books

    Mô hình xem trống ASP.NET MVC

    Nếu ngoại lệ xảy ra khi tham chiếu thuộc tính null trong chế độ xem ASP.NET MVC, bạn cần hiểu rằng p1.Books được đặt trong phương thức hành động của bạn, khi bạn xem p1.Books.Add(...). Khi bạn trả về một mô hình trống (hoặc thuộc tính mô hình) từ bộ điều khiển của bạn, ngoại lệ xảy ra khi các khung nhìn truy cập vào nó:

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

    Thứ tự và sự kiện tạo điều khiển WPF

    Các điều khiển WPF được tạo trong cuộc gọi đến

    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.
    
    theo thứ tự chúng xuất hiện trong cây trực quan. Một
    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.
    
    sẽ được nâng lên trong trường hợp các điều khiển được tạo sớm với các trình xử lý sự kiện, v.v., bắn trong
    Dictionary<string, int> agesForNames = null;
    int age = agesForNames["Bob"]; // agesForNames is null.
                                   // There is no Dictionary to perform the lookup.
    
    tham chiếu các điều khiển được tạo muộn.

    Ví dụ:

    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.
    

    Tại đây

    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
        }
    }
    
    được tạo trước
    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);
        }
    }
    
    . Nếu
    private Customer _customer;
    
    cố gắng tham chiếu `nhãn1, nó sẽ chưa được tạo.
    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!";
        }
    }
    

    Thay đổi thứ tự khai báo trong XAML (tức là, liệt kê

    // if the "FirstName" session value has not yet been set,
    // then this line will throw a NullReferenceException
    string firstName = Session["FirstName"].ToString();
    
    trước @Model, bỏ qua các vấn đề về triết lý thiết kế, ít nhất sẽ giải quyết Model tại đây.

    Truyền với 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 -->
    

    Điều này không ném UnlimitedCastException nhưng trả về InitializeComponent khi diễn viên thất bại (và khi someObject tự nó là null). Vì vậy, hãy nhận thức về điều đó.

    LINQ FirstOrDefault () và SingleOrDefault ()

    Các phiên bản đơn giản NullReferenceExceptionInitializeComponent ném ngoại lệ khi không có gì. Các phiên bản "OrDefault" trả về null trong trường hợp đó. Vì vậy, hãy nhận thức về điều đó.

    thuyết minh

    <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>
    
    ném khi bạn cố gắng lặp lại bộ sưu tập null. Thường gây ra bởi kết quả không mong muốn comboBox1 từ các phương thức trả về bộ sưu tập. label1

    Ví dụ thực tế hơn - chọn các nút từ tài liệu XML. Sẽ ném nếu các nút không được tìm thấy nhưng gỡ lỗi ban đầu cho thấy tất cả các thuộc tính hợp lệ:

    comboBox1_SelectionChanged Những cách tránh

    Kiểm tra rõ ràng
    private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        label1.Content = comboBox1.SelectedIndex.ToString(); // NullReference here!!
    }
    
    và bỏ qua các giá trị null.

    Nếu đôi khi bạn cho rằng tham chiếu là null, bạn có thể kiểm tra xem nó có phải là label1 trước khi truy cập các thành viên thể hiện:

    comboBox1

    Kiểm tra rõ ràng NullReferenceException và cung cấp giá trị mặc định.

    Các phương thức gọi mà bạn mong đợi trả về một thể hiện có thể trả về as, ví dụ khi không thể tìm thấy đối tượng đang tìm kiếm. Bạn có thể chọn trả về giá trị mặc định khi gặp trường hợp này:

    var myThing = someObject as Thing;
    

    Kiểm tra rõ ràng null từ các cuộc gọi phương thức và ném ngoại lệ tùy chỉnh.

    Bạn cũng có thể ném ngoại lệ tùy chỉnh, chỉ để bắt nó trong mã cuộc gọi:

    First()

    Sử dụng Single() nếu giá trị không bao giờ là foreach, để bắt sự cố sớm hơn ngoại lệ xảy ra.

    Khi bạn biết trong quá trình phát triển, một phương thức có thể có thể, nhưng không bao giờ nên trả về null, bạn có thể sử dụng

     List<int> list = null;    
     foreach(var v in list) { } // exception
    
    để phá vỡ càng sớm càng tốt khi nó xảy ra:
     foreach (var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))
    

    Mặc dù kiểm tra này sẽ không kết thúc trong bản dựng phát hành của bạn , gây ra nó sẽ ném null một lần nữa khi null khi chạy ở chế độ phát hành.

    Sử dụng
    void PrintName(Person p) {
        if (p != null) {
            Console.WriteLine(p.Name);
        }
    }
    
    cho các loại giá trị không thể cung cấp giá trị mặc định khi chúng là null.

    null

    Sử dụng toán tử hợp nhất null:
    string GetCategory(Book b) {
        if (b == null)
            return "Unknown";
        return b.Category;
    }
    
    [C #] hoặc null [VB].

    Tốc ký để cung cấp giá trị mặc định khi gặp phải

    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

    Sử dụng toán tử điều kiện null: null hoặc null cho mảng (có sẵn trong C # 6 và VB.NET 14):

    Điều này đôi khi cũng được gọi là toán tử điều hướng an toàn hoặc toán tử Elvis (sau hình dạng của nó). Nếu biểu thức ở phía bên trái của toán tử là null, thì phía bên phải sẽ không được ước tính và thay vào đó null được trả về. Điều đó có nghĩa là những trường hợp như thế này:

    Debug.Assert()

    Nếu người đó không có tiêu đề, điều này sẽ đưa ra một ngoại lệ vì họ đang cố gắng gọi

    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.
    }
    
    trên một tài sản có giá trị null.

    Trong C # 5 trở xuống, điều này có thể được bảo vệ bằng:

    NullReferenceException

    Bây giờ biến tiêu đề sẽ là null thay vì ném một ngoại lệ. C # 6 giới thiệu một cú pháp ngắn hơn cho việc này:

    book == null

    Điều này sẽ dẫn đến biến tiêu đề là GetValueOrDefault() và cuộc gọi đến null không được thực hiện nếu

    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
    
    ??.

    Tất nhiên, bạn vẫn phải kiểm tra If() để tìm null hoặc sử dụng toán tử điều kiện null cùng với toán tử hợp nhất null (null) để cung cấp giá trị mặc định:

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

    Tương tự như vậy, đối với các mảng, bạn có thể sử dụng ?. như sau:

    ?[x]

    Điều này sẽ làm như sau: Nếu myIntArray là null, biểu thức trả về null và bạn có thể kiểm tra nó một cách an toàn. Nếu nó chứa một mảng, nó sẽ làm như sau:

    var title = person.Title.ToUpper();
    
    và trả về phần tử i th .

    Các kỹ thuật đặc biệt để gỡ lỗi và sửa lỗi null derefs trong các trình vòng lặp

    C # hỗ trợ "khối lặp" (được gọi là "trình tạo" trong một số ngôn ngữ phổ biến khác). Các trường hợp ngoại lệ của Null có thể đặc biệt khó khăn để gỡ lỗi trong các khối lặp vì thực thi bị trì hoãn:

    ToUpper

    Nếu

    var title = person.Title == null ? null : person.Title.ToUpper();
    
    kết quả trong
    var title = person.Title?.ToUpper();
    
    thì null sẽ ném. Bây giờ, bạn có thể nghĩ rằng điều đúng đắn cần làm là: ToUpper

    Tại sao điều này sai?Bởi vì khối lặp không thực sự chạy cho đến person.Title! Cuộc gọi đến null chỉ đơn giản trả về một đối tượng mà khi lặp sẽ chạy khối lặp.

    Bằng cách viết một kiểm tra null như thế này, bạn sẽ ngăn chặn sự hủy bỏ null, nhưng bạn di chuyển ngoại lệ đối số null đến điểm của lặp , không đến điểm của cuộc gọi và đó là rất khó hiểu để gỡ lỗi .

    Cách khắc phục chính xác là:

    title

    Nghĩa là tạo một phương thức trợ giúp riêng có logic khối lặp và một phương thức bề mặt công khai kiểm tra null và trả về iterator. Bây giờ khi ?? được gọi, kiểm tra null sẽ xảy ra ngay lập tức và sau đó

    // 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;
    
    thực thi khi trình tự được lặp lại.

    Nếu bạn kiểm tra nguồn tham chiếu cho LINQ đến các Đối tượng, bạn sẽ thấy kỹ thuật này được sử dụng xuyên suốt. Nó hơi khó viết hơn một chút, nhưng nó làm cho việc sửa lỗi vô hiệu hóa dễ dàng hơn nhiều. Tối ưu hóa mã của bạn để thuận tiện cho người gọi, không phải là sự tiện lợi của tác giả .

    Một lưu ý về các cuộc hội thảo null trong mã không an toàn

    C # có chế độ "không an toàn", đúng như tên gọi, cực kỳ nguy hiểm vì các cơ chế an toàn thông thường cung cấp an toàn bộ nhớ và an toàn loại không được thi hành. Bạn không nên viết mã không an toàn trừ khi bạn hiểu rõ và sâu sắc về cách thức hoạt động của bộ nhớ .

    Ở chế độ không an toàn, bạn cần lưu ý đến hai sự thật quan trọng:

    • hủy bỏ hội thảo một con trỏ null tạo ra ngoại lệ tương tự như việc hủy bỏ tham chiếu null tham chiếu
    • hủy bỏ một con trỏ không null không hợp lệ có thể tạo ra ngoại lệ đó trong một số trường hợp

    Để hiểu lý do tại sao, điều đó giúp hiểu cách .NET tạo ra các ngoại lệ vô hiệu hóa null ngay từ đầu. (Các chi tiết này áp dụng cho .NET chạy trên Windows; các hệ điều hành khác sử dụng các cơ chế tương tự.)

    Bộ nhớ được ảo hóa trong Windows; mỗi tiến trình có một không gian bộ nhớ ảo gồm nhiều "trang" bộ nhớ được hệ điều hành theo dõi. Mỗi trang của bộ nhớ có các cờ được đặt trên đó để xác định cách sử dụng: đọc từ, ghi vào, thực thi, v.v. Trang thấp nhất được đánh dấu là "tạo ra lỗi nếu được sử dụng theo bất kỳ cách nào".

    Cả con trỏ null và tham chiếu null trong C # đều được biểu thị bên trong dưới dạng số 0 và do đó, bất kỳ nỗ lực nào để đưa nó vào bộ nhớ tương ứng của nó đều khiến hệ điều hành gây ra lỗi. Thời gian chạy .NET sau đó phát hiện lỗi này và biến nó thành ngoại lệ vô hiệu hóa null.

    Đó là lý do tại sao hội thảo cả con trỏ null và tham chiếu null tạo ra cùng một ngoại lệ.

    Còn điểm thứ hai thì sao? Dereferences any con trỏ không hợp lệ rơi vào trang thấp nhất của bộ nhớ ảo gây ra lỗi hệ điều hành tương tự và do đó cũng có ngoại lệ tương tự.

    Tại sao điều này có ý nghĩa? Chà, giả sử chúng ta có một cấu trúc chứa hai số nguyên và một con trỏ không được quản lý bằng null. Nếu chúng tôi cố gắng hủy đăng ký int thứ hai trong cấu trúc, CLR sẽ không cố truy cập vào bộ lưu trữ ở vị trí 0; nó sẽ truy cập vào bộ lưu trữ tại vị trí bốn. Nhưng về mặt logic, đây là một sự vô hiệu hóa bởi vì chúng tôi đang đến địa chỉ đó thông qua null.

    Nếu bạn đang làm việc với mã không an toàn và bạn nhận được ngoại lệ vô hiệu hóa null, chỉ cần lưu ý rằng con trỏ vi phạm không cần phải là null. Nó có thể là bất kỳ vị trí nào trong trang thấp nhất và ngoại lệ này sẽ được tạo ra.

        
    2258
    2018-07-18 06: 27: 33Z
    1. Có thể đây là một nhận xét ngu ngốc nhưng không phải là cách đầu tiên và tốt nhất để tránh vấn đề này là khởi tạo đối tượng? Đối với tôi nếu lỗi này xảy ra thường là do tôi quên khởi tạo một cái gì đó như phần tử mảng. Tôi nghĩ rằng nó ít phổ biến hơn để định nghĩa đối tượng là null và sau đó tham chiếu nó. Có thể đưa ra cách giải quyết từng vấn đề liền kề với mô tả. Vẫn là một bài viết tốt.
      2014-05-20 06: 39: 13Z
    2. Điều gì xảy ra nếu không có đối tượng, mà là giá trị trả về từ một phương thức hoặc thuộc tính?
      2014-05-20 06: 41: 02Z
    3. Ví dụ về cuốn sách /tác giả hơi kỳ lạ .... Làm thế nào mà nó thậm chí còn biên dịch? Làm thế nào để intellisense thậm chí làm việc? Điều này là gì tôi không tốt với máy tính ...
      2014-09-08 18: 26: 23Z
    4. @ Will: lần chỉnh sửa cuối cùng của tôi có giúp được không? Nếu không, xin vui lòng nói rõ hơn về những gì bạn thấy là một vấn đề.
      2014-09-08 18: 41: 50Z
    5. @ JohnSaunders Ồ, không, xin lỗi, ý tôi là phiên bản khởi tạo đối tượng của điều đó. ?[i] Làm thế nào để khởi tạo bên trong thậm chí ... Tôi không thể nghĩ đến một tình huống mà init bên trong sẽ hoạt động, nhưng nó biên dịch và intellisense hoạt động ... Trừ khi có cấu trúc?
      2014-09-08 18: 44: 35Z
      Ngoại lệ NullReference - Visual Basic

      int[] myIntArray=null;
      var i=5;
      int? elem = myIntArray?[i];
      if (!elem.HasValue) Console.WriteLine("No value");
      
      cho Visual Basic không khác với cái trong C # . Rốt cuộc, cả hai đều báo cáo cùng một ngoại lệ được xác định trong .NET Framework mà cả hai đều sử dụng. Nguyên nhân duy nhất đối với Visual Basic là rất hiếm (có lẽ chỉ có một).

      Câu trả lời này sẽ sử dụng thuật ngữ, cú pháp và ngữ cảnh của Visual Basic. Các ví dụ được sử dụng đến từ một số lượng lớn các câu hỏi Stack Overflow trước đây. Điều này là để tối đa hóa mức độ liên quan bằng cách sử dụng loại của các tình huống thường thấy trong các bài đăng. Một chút giải thích cũng được cung cấp cho những người có thể cần nó. Một ví dụ tương tự như của bạn là rất có thể được liệt kê ở đây.

      Lưu ý:

      1. Đây là dựa trên khái niệm: không có mã để bạn dán vào dự án của mình. Nó nhằm giúp bạn hiểu nguyên nhân gây ra elem = myIntArray[i]; (NRE), cách tìm, cách khắc phục và cách tránh. Một NRE có thể được gây ra theo nhiều cách vì vậy đây không chắc là cuộc gặp gỡ duy nhất của bạn.
      2. Các ví dụ (từ bài đăng Stack Overflow) không phải lúc nào cũng hiển thị cách tốt nhất để làm điều gì đó ở vị trí đầu tiên.
      3. Thông thường, biện pháp khắc phục đơn giản nhất được sử dụng.

      Ý nghĩa cơ bản

      Thông báo "Đối tượng không được đặt thành phiên bản của Đối tượng" có nghĩa là bạn đang cố gắng sử dụng một đối tượng chưa được khởi tạo. Điều này làm sôi một trong những điều sau:

      • Mã của bạn đã khai báo một biến đối tượng, nhưng nó không khởi tạo nó (tạo một thể hiện hoặc ' khởi tạo ' nó)
      • Một cái gì đó mà mã của bạn giả định sẽ khởi tạo một đối tượng, không
      • Có thể, mã khác bị vô hiệu hóa sớm một đối tượng vẫn đang được sử dụng

      Tìm nguyên nhân

      Vì vấn đề là một tham chiếu đối tượng là

      public IEnumerable<Frob> GetFrobs(FrobFactory f, int count)
      {
          for (int i = 0; i < count; ++i)
            yield return f.MakeFrob();
      }
      ...
      FrobFactory factory = whatever;
      IEnumerable<Frobs> frobs = GetFrobs();
      ...
      foreach(Frob frob in frobs) { ... }
      
      , câu trả lời là kiểm tra chúng để tìm ra cái nào. Sau đó xác định lý do tại sao nó không được khởi tạo. Giữ chuột trên các biến khác nhau và Visual Studio (VS) sẽ hiển thị giá trị của chúng - thủ phạm sẽ là whatever.

      Hiển thị gỡ lỗi IDE

      Bạn cũng nên xóa mọi khối Thử /Bắt khỏi mã có liên quan, đặc biệt là các khối không có gì trong khối Bắt. Điều này sẽ khiến mã của bạn bị sập khi nó cố sử dụng một đối tượng là null. Đây là điều bạn muốn vì nó sẽ xác định chính xác vị trí của vấn đề bạn xác định đối tượng gây ra nó.

      A MakeFrob trong Catch hiển thị

      // DON'T DO THIS
      public IEnumerable<Frob> GetFrobs(FrobFactory f, int count)
      {
          if (f == null) 
            throw new ArgumentNullException("f", "factory must not be null");
          for (int i = 0; i < count; ++i)
            yield return f.MakeFrob();
      }
      
      sẽ giúp ích rất ít. Phương pháp này cũng dẫn đến các câu hỏi rất tệ Stack Overflow, bởi vì bạn không thể mô tả ngoại lệ thực tế, đối tượng liên quan hoặc thậm chí dòng mã nơi nó xảy ra.

      Bạn cũng có thể sử dụng foreach ( Gỡ lỗi - > Windows - > Người địa phương ) để kiểm tra các đối tượng của bạn.

      Khi bạn đã biết vấn đề là gì và ở đâu, thường khá dễ khắc phục và nhanh hơn so với việc đăng câu hỏi mới.

      Xem thêm:

      Ví dụ và biện pháp khắc phục

      Đối tượng lớp /Tạo một thực thể

      GetFrobs

      Vấn đề là

      // DO THIS
      public IEnumerable<Frob> GetFrobs(FrobFactory f, int count)
      {
          // No yields in a public method that throws!
          if (f == null) 
            throw new ArgumentNullException("f", "factory must not be null");
          return GetFrobsForReal(f, count);
      }
      private IEnumerable<Frob> GetFrobsForReal(FrobFactory f, int count)
      {
          // Yields in a private method
          Debug.Assert(f != null);
          for (int i = 0; i < count; ++i)
            yield return f.MakeFrob();
      }
      
      không tạo đối tượng CashRegister ; nó chỉ khai báo một biến có tên GetFrobs của Loại đó. Khai báo một biến đối tượng và tạo một thể hiện là hai điều khác nhau.

      Biện pháp

      Toán tử GetFrobsForReal thường có thể được sử dụng để tạo cá thể khi bạn khai báo:

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

      Khi nó chỉ phù hợp vớitạo ví dụ sau:

      NullReference Exception

      Lưu ý: Không sử dụng lại NullReferenceException trong quy trình, bao gồm cả công cụ xây dựng (Nothing):

      Nothing

      Điều này sẽ tạo ra một biến cục bộ , Nothing, chỉ tồn tại trong bối cảnh đó (phụ). Biến MsgBox với cấp mô-đun Error while... mà bạn sẽ sử dụng ở mọi nơi khác vẫn là Locals Window.

        

      Thiếu toán tử

      Dim reg As CashRegister
      ...
      TextBox1.Text = reg.Amount         ' NRE
      
      là nguyên nhân số 1 của Dim được thấy trong các câu hỏi về Stack Overflow được xem xét.

           

      Visual Basic cố gắng làm cho quá trình rõ ràng lặp đi lặp lại bằng cách sử dụng reg : Sử dụng toán tử 060035099111100135035062 tạo một đối tượng mới và gọi 060035099 - hàm tạo - nơi đối tượng của bạn có thể thực hiện bất kỳ khởi tạo nào khác.

      Để rõ ràng, New (hoặc

      Dim reg As New CashRegister        ' [New] creates instance, invokes the constructor
      
      ' Longer, more explicit form:
      Dim reg As CashRegister = New CashRegister
      
      ) chỉ khai báo một biến và
      Private reg As CashRegister         ' Declare
        ...
      reg = New CashRegister()            ' Create instance
      
      . Phạm vi của biến đó - cho dù nó tồn tại cho toàn bộ mô-đun là cục bộ của một thủ tục - được xác định bởi trong đó nó được khai báo. Dim xác định cấp độ truy cập, không phải Phạm vi .

      Để biết thêm thông tin, hãy xem:

      Mảng

      Mảng cũng phải được khởi tạo:

      Sub New

      Mảng này chỉ được khai báo, chưa được tạo. Có một số cách để khởi tạo một mảng:

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

      Lưu ý: Bắt đầu với VS 2010, khi khởi tạo một mảng cục bộ bằng chữ và reg, regScope là các tùy chọn:

      Nothing

      Kiểu dữ liệu và kích thước mảng được suy ra từ dữ liệu được gán. Khai báo cấp độ lớp /mô-đun vẫn yêu cầu New với NullReference Exceptions:

      New

      Ví dụ: Mảng các đối tượng lớp

      New

      Mảng đã được tạo, nhưng các đối tượng Sub New không có.

      Biện pháp

      Dim

      Sử dụng Private sẽ khiến việc có một phần tử không có đối tượng hợp lệ:

      khá khó khăn. Type

      Để biết thêm thông tin, hãy xem:

      Danh sách và Bộ sưu tập

      Bộ sưu tập .NET (trong đó có nhiều loại - Danh sách, Từ điển, v.v.) cũng phải được khởi tạo hoặc tạo.

      Private | Friend | Public

      Bạn nhận được cùng một ngoại lệ vì cùng một lý do -

      Private arr as String()
      
      chỉ được khai báo, nhưng không có trường hợp nào được tạo. Biện pháp khắc phục là như nhau:
      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) {}
      

      Một giám sát chung là một lớp sử dụng bộ sưu tập Option Infer:

      As <Type>

      Cả hai thủ tục sẽ dẫn đến một NRE, vì New chỉ được khai báo, không được khởi tạo. Tạo một thể hiện của

      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}
      
      cũng sẽ không tạo ra một thể hiện của As <Type> bên trong. Đây có thể là ý định thực hiện điều này trong hàm tạo: Option Strict

      Như trước đây, điều này không chính xác:

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

      Để biết thêm thông tin, hãy xem

      Dim arrFoo(5) As Foo
      
      For i As Integer = 0 To arrFoo.Count - 1
         arrFoo(i).Bar = i * 10       ' Exception
      Next
      
      Lớp .

      Đối tượng nhà cung cấp dữ liệu

      Làm việc với cơ sở dữ liệu mang lại nhiều cơ hội cho NullReference vì có thể có nhiều đối tượng (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
      
      ,
      Private myList As List(Of String)
      ..
      myList.Add("ziggy")           ' NullReference
      
      , myList ....) đang sử dụng cùng một lúc. Lưu ý: Không quan trọng bạn đang sử dụng nhà cung cấp dữ liệu nào - MySQL, SQL Server, OleDB, v.v. - khái niệm giống nhau.

      Ví dụ 1

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

      Như trước đây, đối tượng Dataset Type đã được khai báo, nhưng một trường hợp không bao giờ được tạo.

      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
      
      sẽ điền vào barList hiện tại, không tạo một. Trong trường hợp này, vì Foo là biến cục bộ, IDE cảnh báo bạn rằng điều này có thể xảy ra:

      img

      Khi được khai báo là biến cấp mô-đun /lớp, dường như là trường hợp với barList, trình biên dịch không thể biết liệu đối tượng có được tạo bởi thủ tục ngược dòng hay không. Đừng bỏ qua các cảnh báo.

      Biện pháp

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

      Ví dụ 2

      Public Sub New()
          ' Creates another barList local to this procedure
           Dim barList As New List(Of Bar)
      End Sub
      
      . Một vấn đề tiềm năng khác là giả sử sẽ có List(Of T) có thể không phải như vậy khi SQL bao gồm mệnh đề WHERE.

      Biện pháp

      Vì việc này sử dụng một bảng, sử dụng Command sẽ tránh được lỗi chính tả. Kiểm tra Connection cũng có thể giúp:

      Transaction

      Dataset là một hàm trả về số DataTable cũng có thể được kiểm tra:

      DataRows

      Ví dụ 3

      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 sẽ cung cấp DataAdapter như trong ví dụ trước, nhưng nó không phân tích tên từ bảng SQL hoặc cơ sở dữ liệu. Do đó, DataSet tham chiếu một bảng không tồn tại.

      Biện pháp giống nhau, tham chiếu bảng theo chỉ mục:

      ds

      Xem thêm Lớp DataTable .

      Đường dẫn đối tượng /lồng nhau

      con

      Mã chỉ đang thử nghiệm

      Dim ds As New DataSet
      
      trong khi cả
      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 cũng có thể là Không có gì. biện pháp khắc phục là kiểm tra toàn bộ chuỗi hoặc đường dẫn của các đối tượng một lần: Employee

      DataTable rất quan trọng. Các thử nghiệm tiếp theo sẽ không được thực hiện khi gặp điều kiện NullReferenceException đầu tiên. Điều này cho phép mã 'khoan' một cách an toàn vào (các) đối tượng một cấp 'tại một thời điểm, đánh giá Items chỉ sau khi (và nếu) Tables(0) được xác định là hợp lệ. Chuỗi đối tượng hoặc đường dẫn có thể khá dài khi mã hóa các đối tượng phức tạp:

      Rows.Count

      Không thể tham chiếu bất cứ điều gì 'xuôi dòng' của một đối tượng

      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
      
      . Điều này cũng áp dụng cho các điều khiển: Fill

      Tại đây, Rows hoặc

      If da.Fill(ds, "Employees") > 0 Then...
      
      có thể không là gì hoặc yếu tố
      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
      
      có thể không tồn tại.

      Điều khiển giao diện người dùng

      DataAdapter

      Trong số những thứ khác, mã này không lường trước được rằng người dùng có thể không chọn thứ gì đó trong một hoặc nhiều điều khiển UI. TableNames cũng có thể là ds.Tables("TICKET_RESERVATION"), vì vậy

      If ds.Tables(0).Rows.Count > 0 Then
      
      sẽ dẫn đến một NRE.

      Biện pháp

      Xác thực dữ liệu trước khi sử dụng (cũng sử dụng

      If myFoo.Bar.Items IsNot Nothing Then
         ...
      
      và các tham số SQL): Items Ngoài ra, bạn có thể sử dụng myFoo

      Các hình thức cơ bản trực quan

      Bar

      Đây là một cách khá phổ biến để nhận NRE. Trong C #, tùy thuộc vào cách mã hóa, IDE sẽ báo cáo rằng

      If (myFoo IsNot Nothing) AndAlso
          (myFoo.Bar IsNot Nothing) AndAlso
          (myFoo.Bar.Items IsNot Nothing) Then
          ....
      
      không tồn tại trong ngữ cảnh hiện tại hoặc "không thể tham chiếu thành viên không tĩnh". Vì vậy, ở một mức độ nào đó, đây là một tình huống chỉ có VB. Nó cũng phức tạp vì nó có thể dẫn đến một thác thất bại.

      Các mảng và bộ sưu tập không thể được khởi tạo theo cách này. Mã khởi tạo này sẽ chạy trước hàm tạo tạo AndAlso hoặc False.

      • Danh sách và Bộ sưu tập sẽ đơn giản trống
      • Mảng sẽ chứa năm yếu tố Không có gì
      • Việc chuyển nhượng myFoo.Bar sẽ dẫn đến NRE ngay lập tức vì Không có gì không có tài sản myFoo

      Tham chiếu các phần tử mảng sau này sẽ dẫn đến NRE. Nếu bạn thực hiện việc này trong

      myBase.myNodes(3).Layer.SubLayer.Foo.Files.Add("somefilename")
      
      , do một lỗi lạ, IDE có thể không báo cáo ngoại lệ khi nó xảy ra. Ngoại lệ sẽ bật lên sau khi mã của bạn cố gắng sử dụngcác mảng. "Ngoại lệ im lặng" này là chi tiết trong bài đăng này . Đối với mục đích của chúng tôi, mấu chốt là khi có sự cố thảm khốc xảy ra trong khi tạo biểu mẫu (null hoặc
      myWebBrowser.Document.GetElementById("formfld1").InnerText = "some value"
      
      ), các trường hợp ngoại lệ có thể không được đưa ra, mã sẽ thoát khỏi quy trình và chỉ hiển thị biểu mẫu.

      Vì không có mã nào khác trong sự kiện myWebBrowser hoặc Document của bạn sẽ chạy sau NRE, rất nhiều điều tuyệt vời khác có thể không được khởi tạo.

      formfld1

      Lưu ý điều này áp dụng cho bất kỳ và tất cả các tham chiếu kiểm soát và thành phần làm cho những điều này là bất hợp pháp ở nơi chúng:

      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)
      

      Biện pháp khắc phục một phần

      Thật tò mò rằng VB không đưa ra cảnh báo, nhưng biện pháp khắc phục là khai báo các thùng chứa ở cấp biểu mẫu, nhưng khởi tạo chúng trong trình xử lý sự kiện tải biểu mẫu khi các điều khiển do tồn tại. Điều này có thể được thực hiện trong ListBox1.SelectedItem miễn là mã của bạn sau cuộc gọi Nothing:

      ListBox1.SelectedItem.ToString

      Mã mảng có thể chưa ra khỏi rừng. Bất kỳ điều khiển nào trong bộ điều khiển container (như Option Strict hoặc

      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
      
      ) sẽ không được tìm thấy trong (ComboBox5.SelectedItem IsNot Nothing) AndAlso...; chúng sẽ nằm trong bộ sưu tập Điều khiển của Bảng điều khiển hoặc GroupBox đó. Một điều khiển cũng sẽ không được trả về khi tên điều khiển bị sai chính tả (
      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
      
      ). Trong các trường hợp như vậy, Controls sẽ lại được lưu trữ trong các phần tử mảng đó và NRE sẽ dẫn đến khi bạn cố gắng tham chiếu nó.

      Chúng nên dễ dàng tìm thấy ngay bây giờ khi bạn biết những gì bạn đang tìm kiếm: VS hiển thị cho bạn lỗi theo cách của bạn

      "Nút2" nằm trên số Form

      Biện pháp

      Thay vì tham chiếu gián tiếp theo tên bằng bộ sưu tập Controls của biểu mẫu, hãy sử dụng tham chiếu điều khiển:

      somevar

      Chức năng hoàn trả không có gì

      .Text

      Đây là trường hợp IDE sẽ cảnh báo bạn rằng ' không phải tất cả các đường dẫn đều trả về giá trị và Form_Load có thể dẫn đến '. Bạn có thể loại bỏ cảnh báo, bằng cách thay thế Sub New bằng Form Load, nhưng điều đó không giải quyết được vấn đề. Bất cứ điều gì cố gắng sử dụng trả lại khi Sub New sẽ dẫn đến NRE:

      Form Load

      Biện pháp

      Thay thế

      Sub Form_Load(..._
         '...
         Dim name As String = NameBoxes(2).Text        ' NRE
         ' ...
         ' More code (which will likely not be executed)
         ' ...
      End Sub
      
      trong chức năng bằng
      Public Class Form1
      
          Private myFiles() As String = Me.OpenFileDialog1.FileName & ...
          Private dbcon As String = OpenFileDialog1.FileName & ";Jet Oledb..."
          Private studentName As String = TextBox13.Text
      
      . Trả lại trống Sub New không giống như trả lại InitializeComponent. p>
      ' 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
      

      Thử /bắt được triển khai kém

      Thử /Bắt được triển khai kém có thể che giấu sự cố và dẫn đến sự cố mới:

      GroupBox

      Đây là trường hợp một đối tượng không được tạo như mong đợi, nhưng cũng cho thấy tính hữu dụng của bộ đếm trống Panel.

      . kết quả Me.Controls mới.

      Một khối "TeStBox2" trống là sân chơi của quỷ. OP này đã gặp khó khăn tại sao anh ta nhận được một NRE trong khối Nothing. Trong các tình huống khác, Panel trống có thể dẫn đến một điều gì đó khác đi sâu hơn về phía trước và khiến bạn mất thời gian nhìn vào những thứ sai ở vị trí sai cho vấn đề. ("Ngoại lệ im lặng" được mô tả ở trên cung cấp cùng một giá trị giải trí.)

      Biện pháp

      Không sử dụng các khối Thử /Bắt trống - hãy để mã bị sập để bạn có thể a) xác định nguyên nhân b) xác định vị trí và c) áp dụng một biện pháp khắc phục thích hợp. Các khối Thử /Bắt không nhằm che giấu ngoại lệ khỏi người đủ điều kiện duy nhất để sửa chúng - nhà phát triển.

      DBNull không giống với Không có gì

      Controls

      Hàm

      ' 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...})
      
      được sử dụng để kiểm tra xem giá trị có bằng
      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
      
      :

      Sau đó, Bắt đầu với gỡ lỗi (F5) hoặc Đính kèm [Trình gỡ lỗi VS] vào Quá trình chạy . Thỉnh thoảng, có thể hữu ích khi sử dụng object == null , sẽ nhắc khởi chạy trình gỡ lỗi.

      Bây giờ, khi ném NullReferenceException (hoặc chưa xử lý), trình gỡ lỗi sẽ dừng (nhớ quy tắc được đặt ở trên?) trên dòng xảy ra ngoại lệ. Đôi khi lỗi sẽ dễ dàng phát hiện.

      Chẳng hạn, trong dòng sau đây, mã duy nhất mà có thể gây ra ngoại lệ là nếu

      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
      }
      
      ước tính thành null. Điều này có thể được xác minh bằng cách xem Cửa sổ xem hoặc chạy các biểu thức trong Cửa sổ ngay lập tức . Nothing . null

      Khi nơi ngoại lệ được ném đã được định vị, việc lập luận ngược lại để tìm ra giá trị null được [không chính xác] được giới thiệu -

      Dành thời gian cần thiết để hiểu nguyên nhân của ngoại lệ. Kiểm tra các biểu thức null. Kiểm tra các biểu thức trước đó có thể dẫn đến các biểu thức null như vậy. Thêm điểm dừng và bước qua chương trình khi thích hợp. Sử dụng trình gỡ lỗi.

      1 Nếu Break on Ném quá mạnh vàtrình gỡ lỗi dừng trên một NPE trong thư viện .NET hoặc bên thứ 3, Phá vỡ người dùng- Chưa xử lý có thể được sử dụng để hạn chế các ngoại lệ bắt được. Ngoài ra, VS2012 giới thiệu Chỉ mã của tôi mà tôi khuyên bạn cũng nên bật.

        

      Nếu bạn đang gỡ lỗi với Just My Code được bật, hành vi sẽ hơi khác. Khi Just My Code được bật, trình gỡ lỗi bỏ qua các ngoại lệ thời gian chạy ngôn ngữ chung (CLR) cơ hội đầu tiên được đưa ra ngoài Mã của tôi và không chuyển qua Mã của tôi

          
      59
      2018-07-18 06: 42: 11Z

      Simon Mourier đã đưa ra ví dụ này :

      Nothing

      trong đó một chuyển đổi unboxing (diễn viên) từ null (hoặc từ một trong các lớp Nothing hoặc null đến một loại giá trị (khác với Nothing) tự nó cung cấp cho null.

      Theo hướng khác, một quyền anh chuyển đổi từ a

      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
      } 
      
      Person p = null;
      p.Name = "Harry"; // NullReferenceException occurs here.
      
      bằng
      Person p = null;
      if (p!=null)
      {
          p.Name = "Harry"; // Not going to run to this point
      }
      
      thành loại tham chiếu, có thể cung cấp tham chiếu NullReferenceExceptions mà sau đó có thể dẫn đến as. Ví dụ cổ điển là:
      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
      

      Đôi khi quyền anh xảy ra theo cách khác. Ví dụ: với phương thức mở rộng không chung chung này:

      Book

      đoạn mã sau sẽ có vấn đề:

      Car

      Những trường hợp này phát sinh do các quy tắc đặc biệt mà thời gian chạy sử dụng khi quyền anh Car.

          
      55
      2018-07-18 06: 34: 19Z

      Thêm trường hợp khi tên lớp cho thực thể được sử dụng trong khung thực thể giống với tên lớp cho tệp mã phía sau của biểu mẫu web.

      Giả sử bạn có một biểu mẫu web Contact.aspx có lớp cơ sở mã là Liên hệ và bạn có tên thực thể Liên hệ.

      Sau đó, đoạn mã sau sẽ đưa ra một NullReferenceException khi bạn gọi bối cảnh.SaveChanges ()

      Book

      Để hoàn thành lớp DataContext

      as

      và lớp thực thể Liên hệ. Đôi khi các lớp thực thể là các lớp một phần để bạn cũng có thể mở rộng chúng trong các tệp khác.

      null

      Lỗi xảy ra khi cả lớp thực thể và lớp cơ sở trong cùng một không gian tên. Để sửa lỗi này, đổi tên lớp thực thể hoặc lớp codebehind cho Contact.aspx.

      Lý do Tôi vẫn không chắc chắn về lý do. Nhưng bất cứ khi nào bất kỳ lớp thực thể nào sẽ mở rộng System.Web.UI.Page thì lỗi này xảy ra.

      Để thảo luận, hãy xem NullReferenceException trong DbContext.saveChanges ()

          
      40
      2017-05-23 12: 34: 45Z

      Một trường hợp chung khác mà người ta có thể nhận được ngoại lệ này liên quan đến các lớp chế nhạo trong quá trình kiểm tra đơn vị. Bất kể khung mô phỏng đang được sử dụng, bạn phải đảm bảo rằng tất cả các mức phù hợp của hệ thống phân cấp lớp được chế giễu đúng. Đặc biệt, tất cả các thuộc tính của mybook được tham chiếu bởi mã được kiểm tra phải được chế giễu.

      Xem "

nguồn đặt đây