etc./StackOverFlow

NullReferenceException이란 무엇이며 어떻게 수정합니까?

청렴결백한 만능 재주꾼 2021. 12. 21. 22:08
반응형

질문자 :Community Wiki


몇 가지 코드가 있고 실행될 때 NullReferenceException throw하여 다음과 같이 말합니다.

개체 참조가 개체의 인스턴스로 설정되지 않았습니다.

이것은 무엇을 의미하며 이 오류를 수정하려면 어떻게 해야 합니까?



원인은 무엇입니까?

결론

null (또는 VB.NET에서는 Nothing 것을 사용하려고 합니다. 이것은 null 설정하거나 전혀 설정하지 않았음을 의미합니다.

다른 것과 마찬가지로 null 이 전달됩니다. 메서드 "A" 에서 null 경우 메서드 "B"가 메서드 "A"에 null

null 은 다른 의미를 가질 수 있습니다.

  1. 초기화되지 않아 아무 것도 가리키지 않는 개체 변수입니다. 이 경우 이러한 개체의 멤버에 액세스하면 NullReferenceException 이 발생합니다.
  2. 개발자는 의미 있는 값을 사용할 수 없음을 나타내기 위해 의도적으로 null 사용하고 있습니다. C#에는 변수에 대한 nullable 데이터 유형의 개념이 있습니다(예: 데이터베이스 테이블에 nullable 필드가 있을 수 있음). 변수에 null 을 할당하여 저장된 값이 없음을 나타낼 수 있습니다(예: int? a = null; Nullable<int> a = null; 의 단축키임) 여기서 물음표는 변수 a null 을 저장할 수 있음을 나타냅니다. if (a.HasValue) {...} 또는 if (a==null) {...} 있습니다. 널 변수처럼 이 예를 통해 액세스 할 수 있도록 값 a a.Value 통해 명시 적으로, 또는 단지 정상적으로 . a
    을 통해 접속합니다 a.Value 발생 InvalidOperationException 대신의 NullReferenceException 하는 경우 a 이다 null - 당신이 다른 비 - 널 (NULL) 변수가있는 경우는, 사전에 예를 체크를해야 int b; 그런 다음 if (a.HasValue) { b = a.Value; } 이하 if (a != null) { b = a; } .

NullReferenceException 이어질 수 있는 많은 프로그래머가 자주 범하는 실수를 보다 자세히 설명합니다.

더 구체적으로

NullReferenceException 던지는 runtime 은 항상 같은 의미입니다. 참조를 사용하려고 하는데 참조가 초기화되지 않았습니다(또는 한 번 초기화되었지만 더 이상 초기화되지 않음).

이는 참조가 null null 참조를 통해 멤버(예: 메서드)에 액세스할 수 없음을 의미합니다. 가장 간단한 경우:

 string foo = null; foo.ToUpper();

null 가리키는 string ToUpper() 를 호출할 수 없기 때문에 두 번째 줄에서 NullReferenceException 이 발생합니다.

디버깅

NullReferenceException 의 소스를 어떻게 찾습니까? 예외가 발생한 위치에서 정확히 throw되는 예외 자체를 보는 것 외에도 Visual Studio의 일반적인 디버깅 규칙이 적용됩니다. 전략적 중단점을 배치하고 변수를 검사합니다. 빠른) Watch 창 또는 Locals 및 Autos와 같은 다양한 디버깅 패널을 사용합니다.

참조가 설정되거나 설정되지 않은 위치를 찾으려면 해당 이름을 마우스 오른쪽 버튼으로 클릭하고 "모든 참조 찾기"를 선택합니다. 그런 다음 발견된 모든 위치에 중단점을 배치하고 디버거가 연결된 상태에서 프로그램을 실행할 수 있습니다. 디버거가 이러한 중단점에서 중단될 때마다 참조가 null이 아닌 것으로 예상하는지 확인하고, 변수를 검사하고, 예상할 때 인스턴스를 가리키는지 확인해야 합니다.

이 방법으로 프로그램 흐름을 따르면 인스턴스가 null이 아니어야 하는 위치와 올바르게 설정되지 않은 이유를 찾을 수 있습니다.

예외가 발생할 수 있는 몇 가지 일반적인 시나리오:

일반적인

 ref1.ref2.ref3.member

ref1 또는 ref2 또는 ref3이 null이면 NullReferenceException 합니다. 문제를 해결하려면 표현식을 더 간단한 등가로 다시 작성하여 어느 것이 null인지 찾으십시오.

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

특히 HttpContext.Current.User.Identity.Name 에서 HttpContext.Current 는 null이거나 User 속성이 null이거나 Identity 속성이 null일 수 있습니다.

간접

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

자식(Person) null 참조를 피하려면 부모(Book) 개체의 생성자에서 초기화할 수 있습니다.

중첩 객체 이니셜라이저

중첩된 객체 이니셜라이저에도 동일하게 적용됩니다.

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

이것은 다음과 같이 번역됩니다.

 Book b1 = new Book(); b1.Author.Age = 45;

new 키워드가 사용되는 동안 Book 의 새 인스턴스만 생성 Person 의 새 인스턴스는 Author 속성은 여전히 null 입니다.

중첩 컬렉션 이니셜라이저

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

중첩 컬렉션 Initializers 는 다음과 같이 동일하게 작동합니다.

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

이것은 다음과 같이 번역됩니다.

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

new Person Person 의 인스턴스만 생성하지만 Books 컬렉션은 여전히 null 입니다. 컬렉션 Initializer p1.Books 대한 컬렉션을 생성하지 않으며 p1.Books.Add(...) 문으로만 변환됩니다.

정렬

 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.

이벤트(C#)

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

(참고: VB.NET 컴파일러는 이벤트 사용에 대해 null 검사를 삽입하므로 VB.NET에서 Nothing

잘못된 명명 규칙:

필드 이름을 지역 이름과 다르게 지정한 경우 필드를 초기화한 적이 없다는 것을 깨달았을 수 있습니다.

 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 MVC 빈 보기 모델

ASP.NET MVC View 에서 @Model 의 속성을 참조할 때 예외가 발생하면 return 할 때 작업 메서드에서 Model 이 설정된다는 점을 이해해야 합니다. 컨트롤러에서 빈 모델(또는 모델 속성)을 반환하면 뷰에서 액세스할 때 예외가 발생합니다.

 // 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 -->

WPF 컨트롤 생성 순서 및 이벤트

WPF 컨트롤은 시각적 트리에 나타나는 순서대로 InitializeComponent 를 호출하는 동안 생성됩니다. 늦게 생성된 컨트롤을 참조 InitializeComponent 동안 발생하는 이벤트 핸들러 등으로 일찍 생성된 컨트롤의 경우 NullReferenceException

예를 들어:

 <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 전에 생성됩니다. comboBox1_SelectionChanged 가 `label1'을 참조하려고 하면 아직 생성되지 않은 것입니다.

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

의 선언의 순서 변경 XAML (즉, 목록 label1 하기 전에 comboBox1 디자인 철학의 문제를 무시하고) 적어도 해결할 것 NullReferenceException 여기에.

와 캐스트 as

 var myThing = someObject as Thing;

InvalidCastException 시키지 않지만 캐스트가 실패할 때(그리고 someObject 자체가 null인 경우) null 반환합니다. 그러니 알아두세요.

LINQ FirstOrDefault()SingleOrDefault()

일반 버전의 First()Single() 은 아무것도 없을 때 예외를 throw합니다. 이 경우 "OrDefault" 버전은 null 을 반환합니다. 그러니 알아두세요.

각각

null 컬렉션을 반복하려고 하면 foreach 일반적으로 컬렉션을 반환하는 메서드의 null 결과로 인해 발생합니다.

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

보다 현실적인 예 - XML 문서에서 노드를 선택합니다. 노드를 찾을 수 없지만 초기 디버깅에서 모든 속성이 유효한 것으로 표시되면 throw됩니다.

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

피하는 방법

명시적으로 null 확인하고 null 값을 무시합니다.

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

null 을 명시적으로 확인하고 사용자 지정 예외를 throw합니다.

호출 코드에서만 예외를 포착하기 위해 사용자 정의 예외를 던질 수도 있습니다.

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

null 이 아니어야 하는 경우 Debug.Assert 사용하여 예외가 발생하기 전에 문제를 포착하십시오.

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

이 검사 가 릴리스 빌드에서 끝나지는 않지만 릴리스 모드에서 런타임에 book == null NullReferenceException 다시 발생합니다.

nullable 값 형식에 대해 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

null 병합 연산자 사용: ?? [C#] 또는 If() [VB].

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

null 조건 연산자 사용: ?. 또는 ?[x] (C# 6 및 VB.NET 14에서 사용 가능):

이것은 때때로 안전 탐색 또는 Elvis(모양을 따서) 연산자라고도 합니다. 연산자의 왼쪽에 있는 식이 null이면 오른쪽은 평가되지 않고 대신 null이 반환됩니다. 이는 다음과 같은 경우를 의미합니다.

 var title = person.Title.ToUpper();

사람에게 직함이 없으면 null 값이 있는 속성에서 ToUpper 를 호출하려고 하기 때문에 예외가 발생합니다.

C# 5 이하에서는 다음과 같이 보호할 수 있습니다.

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

이제 제목 변수는 예외를 발생시키는 대신 null이 됩니다. C# 6에는 이에 대한 더 짧은 구문이 도입되었습니다.

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

이렇게 하면 제목 변수가 null person.Titlenull ToUpper 대한 호출이 이루어지지 않습니다.

물론, 여전히 null 대한 title 을 확인하거나 null 조건 연산자를 null 병합 연산자( ?? )와 함께 사용하여 기본값을 제공해야 합니다.

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

마찬가지로 배열의 경우 다음과 같이 ?[i]

 int[] myIntArray = null; var i = 5; int? elem = myIntArray?[i]; if (!elem.HasValue) Console.WriteLine("No value");

이렇게 하면 다음이 수행됩니다. myIntArraynull 표현식이 null 반환하므로 안전하게 확인할 수 있습니다. 배열이 포함되어 있으면 다음과 동일하게 수행됩니다. elem = myIntArray[i]; i 번째 요소를 반환합니다.

null 컨텍스트 사용(C# 8에서 사용 가능):

도입 된 C# 8 , 널 컨텍스트 및 널 참조 유형은 정적 변수 분석을 수행하고 값이 잠재적 될 수 있다면 컴파일러 경고를 제공 null 또는 적이 설정 null . nullable 참조 형식을 사용하면 형식이 명시적으로 null 되도록 허용할 수 있습니다.

csproj 파일 Nullable 요소를 사용하여 프로젝트에 대해 nullable 주석 컨텍스트 및 nullable 경고 컨텍스트를 설정할 수 있습니다. 이 요소는 컴파일러가 형식의 null 허용 여부와 생성되는 경고를 해석하는 방법을 구성합니다. 유효한 설정은 다음과 같습니다.

  • enable : nullable 주석 컨텍스트가 활성화됩니다. nullable 경고 컨텍스트가 활성화되었습니다. 예를 들어 참조 유형 문자열의 변수는 null을 허용하지 않습니다. 모든 null 허용 여부 경고가 활성화됩니다.
  • disable : nullable 주석 컨텍스트가 비활성화됩니다. nullable 경고 컨텍스트가 비활성화되었습니다. 참조 형식의 변수는 이전 버전의 C#과 마찬가지로 인식되지 않습니다. 모든 null 허용 여부 경고가 비활성화됩니다.
  • safeonly : nullable 주석 컨텍스트가 활성화되었습니다. nullable 경고 컨텍스트는 safeonly입니다. 참조 유형의 변수는 null을 허용하지 않습니다. 모든 안전 null 허용 여부 경고가 활성화됩니다.
  • warnings : nullable 주석 컨텍스트가 비활성화되었습니다. nullable 경고 컨텍스트가 활성화되었습니다. 참조 유형의 변수는 무시됩니다. 모든 null 허용 여부 경고가 활성화됩니다.
  • safeonlywarnings : nullable 주석 컨텍스트가 비활성화됩니다. nullable 경고 컨텍스트는 safeonly입니다. 참조 유형의 변수는 무시됩니다. 모든 안전 null 허용 여부 경고가 활성화됩니다.

nullable 참조 형식은 nullable 값 형식과 동일한 구문을 사용하여 표시됩니다 ? 변수의 유형에 추가됩니다.

반복기에서 null deref를 디버깅하고 수정하기 위한 특수 기술

C# 은 "반복자 블록"(일부 다른 인기 있는 언어에서는 "제너레이터"라고 함)을 지원합니다. NullReferenceException 은 실행이 지연되기 때문에 반복자 블록에서 디버그하기가 특히 까다로울 수 있습니다.

 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) { ... }

경우 whatever 결과 null 다음 MakeFrob 발생합니다. 이제 다음과 같이 하는 것이 옳다고 생각할 수 있습니다.

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

이게 왜 잘못된거죠? foreach 까지 실제로 실행 되지 않기 때문입니다! GetFrobs 대한 호출은 단순히 반복 될 때 반복자 블록을 실행할 개체를 반환합니다.

null 검사를 작성 NullReferenceException 을 방지할 수 NullArgumentException 을 호출 지점이 아니라 반복 지점으로 이동하므로 디버그하기가 매우 혼란스럽습니다 .

올바른 수정 사항은 다음과 같습니다.

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

즉, iterator 블록 로직을 가지는 private helper 메소드와 null 체크를 하고 iterator를 리턴하는 public surface 메소드를 만든다. 이제 GetFrobs 가 호출되면 null 검사가 즉시 발생하고 시퀀스가 반복될 때 GetFrobsForReal

LINQ to Objects에 대한 참조 소스를 살펴보면 이 기술이 전체적으로 사용되었음을 알 수 있습니다. 쓰기가 약간 더 투박하지만 nullity 오류 디버깅을 훨씬 쉽게 만듭니다. 작성자의 편의가 아닌 호출자의 편의를 위해 코드를 최적화하십시오 .

안전하지 않은 코드의 null 역참조에 대한 참고 사항

C# 에는 이름에서 알 수 있듯이 메모리 안전과 형식 안전을 제공하는 일반적인 안전 메커니즘이 적용되지 않기 때문에 극도로 위험한 "안전하지 않은" 모드가 있습니다. 메모리 작동 방식에 대한 철저하고 깊은 이해가 없는 한 안전하지 않은 코드를 작성해서는 안 됩니다.

안전하지 않은 모드에서는 두 가지 중요한 사실을 알고 있어야 합니다.

  • null 포인터 를 역참조하면 null 참조 를 역참조하는 것과 동일한 예외가 발생합니다.
  • 유효하지 않은 null이 아닌 포인터를 역참조하면 일부 상황에서 해당 예외가 발생할 수 있습니다.

그 이유를 이해하려면 .NET이 처음에 NullReferenceException 을 생성하는 방법을 이해하는 것이 좋습니다. (이 세부 정보는 Windows에서 실행되는 .NET에 적용되며 다른 운영 체제는 유사한 메커니즘을 사용합니다.)

Windows 에서 가상화됩니다. 각 프로세스는 운영 체제에서 추적하는 많은 메모리 "페이지"의 가상 메모리 공간을 얻습니다. 메모리의 각 페이지에는 읽기, 쓰기, 실행 등 사용 방법을 결정하는 플래그가 설정되어 있습니다. 가장 낮은 페이지는 "어떤 식으로든 사용된 경우 오류 생성"으로 표시됩니다.

C# 에서 null 포인터와 null 참조는 모두 내부적으로 숫자 0으로 표시되므로 해당 메모리 저장소로 역참조하려고 하면 운영 체제에서 오류가 발생합니다. 그런 다음 .NET 런타임은 이 오류를 감지하고 NullReferenceException 으로 바꿉니다.

그렇기 때문에 null 포인터와 null 참조를 모두 역참조하면 동일한 예외가 생성됩니다.

두 번째 점은 어떻습니까? 가상 메모리의 최하위 페이지에 있는 잘못된 포인터를 역참조하면 동일한 운영 체제 오류가 발생하므로 동일한 예외가 발생합니다.

이게 왜 말이 되나요? 음, 두 개의 int를 포함하는 구조체와 null과 같은 관리되지 않는 포인터가 있다고 가정합니다. 구조체에서 두 번째 int를 역참조하려고 하면 CLR 은 위치 0의 저장소에 액세스하려고 시도하지 않습니다. 위치 4의 저장소에 액세스합니다. 그러나 논리적으로 이것은 null을 통해 해당 주소에 도달하기 때문에 null 역참조입니다.

안전하지 않은 코드로 작업하고 NullReferenceException 하는 경우 문제가 되는 포인터가 null일 필요는 없다는 점에 유의하십시오. 가장 낮은 페이지의 모든 위치일 수 있으며 이 예외가 생성됩니다.


Community Wiki

NullReference 예외 — Visual Basic

Visual BasicNullReference Exception 는 C#의 예외와 다르지 않습니다. 결국 그들은 둘 다 사용하는 .NET Framework에 정의된 동일한 예외를 보고하고 있습니다. Visual Basic에 고유한 원인은 드뭅니다(아마도 단 하나).

이 답변은 Visual Basic 용어, 구문 및 컨텍스트를 사용합니다. 사용된 예제는 과거의 수많은 스택 오버플로 질문에서 가져온 것입니다. 이것은 종종 게시물에서 볼 상황의 종류를 사용하여 관련성을 극대화하는 것입니다. 필요하신 분들을 위해 조금 더 자세한 설명도 해드립니다. 귀하와 유사한 예가 여기에 나열될 가능성 이 매우 높습니다.

메모:

  1. 이것은 개념 기반입니다. 프로젝트에 붙여넣을 코드가 없습니다. NullReferenceException )의 원인, 발견 방법, 수정 방법 및 방지 방법을 이해하는 데 도움을 주기 위한 것입니다. NRE는 여러 가지 방법으로 발생할 수 있으므로 이것이 유일한 만남은 아닐 것입니다.
  2. 스택 오버플로 게시물의 예제는 처음부터 무언가를 수행하는 가장 좋은 방법을 항상 보여주지는 않습니다.
  3. 일반적으로 가장 간단한 치료법이 사용됩니다.

기본 의미

"개체가 개체의 인스턴스로 설정되지 않았습니다" 라는 메시지는 초기화되지 않은 개체를 사용하려고 함을 의미합니다. 이것은 다음 중 하나로 요약됩니다.

  • 코드에서 개체 변수를 선언 했지만 초기화 하지 않았습니다(인스턴스를 생성하거나 ' 인스턴스화 ').
  • 귀하의 코드가 개체를 초기화할 것이라고 가정했지만,
  • 다른 코드가 아직 사용 중인 개체를 조기에 무효화했을 수 있습니다.

원인 찾기

Nothing 인 객체 참조이기 때문에 답은 그것들을 조사하여 어느 것을 찾는 것입니다. 그런 다음 초기화되지 않은 이유를 판별하십시오. 다양한 변수 위에 마우스를 가져가면 Visual Studio(VS)에 해당 값이 표시됩니다 Nothing 입니다.

IDE 디버그 디스플레이

또한 관련 코드, 특히 Catch 블록에 아무것도 없는 경우 Try/Catch 블록을 제거해야 합니다. Nothing 인 개체를 사용하려고 할 때 충돌이 발생합니다. 이것은 문제의 정확한 위치 를 식별하고 문제를 일으키는 개체를 식별할 수 있게 해주기 때문에 원하는 것입니다.

Error while... 을 표시하는 Catch의 MsgBox 는 거의 도움이 되지 않습니다. 이 방법은 또한 실제 예외, 관련된 개체 또는 발생하는 코드 행을 설명할 수 없기 때문에 매우 나쁜 스택 오버플로 질문으로 이어집니다.

Locals Window ( Debug -> Windows -> Locals )을 사용하여 개체를 검사할 수도 있습니다.

문제가 무엇이며 어디에 있는지 알게 되면 일반적으로 새 질문을 게시하는 것보다 수정하기 쉽고 빠릅니다.

또한보십시오:

예 및 해결 방법

클래스 객체 / 인스턴스 생성

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

문제는 Dim 이 CashRegister 객체를 생성하지 않는다는 것입니다. 해당 유형의 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

참고: Sub New )를 포함하여 프로시저에서 Dim 다시 사용 하지 마십시오.

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

그러면 해당 컨텍스트(sub)에만 존재 하는 지역 변수 reg 가 생성됩니다. 다른 모든 곳에서 사용할 Scope 모듈 수준의 reg Nothing 유지됩니다.

New 연산자가 누락된 것은 검토된 스택 오버플로 질문에서 볼 수 있는 NullReference Exceptions 의 #1 원인입니다.

Visual Basic의 프로세스가 사용하여 반복적으로 명확하게하려고 New 은 Using : New 운영자 것은 새로운 객체와 통화를 만들어 Sub New 생성자 - - 개체가 다른 초기화를 수행 할 수 있습니다.

분명히 하기 위해 Dim (또는 Private )은 변수와 해당 Type 만 선언 합니다. 변수의 범위( 변수가 전체 모듈/클래스에 대해 존재하는지 또는 프로시저에 대해 로컬인지 여부)는 선언 된 위치에 따라 결정됩니다. Private | Friend | Public 은 Scope가 아닌 액세스 수준을 정의합니다.

자세한 내용은 다음을 참조하세요.


배열

배열도 인스턴스화해야 합니다.

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

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}

데이터 유형 및 배열 크기는 할당되는 데이터에서 유추됩니다. 클래스/모듈 수준 선언에는 여전히 Option Strict As <Type> 이 필요합니다.

 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 는 인스턴스화되지 않고 선언만 되었기 때문에 두 절차 모두 NRE가 됩니다. Foo 의 인스턴스를 barList 내부 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 , DataTable , DataRows ....)를 사용할 수 있기 때문에 NullReference에 대한 많은 기회를 제공합니다. 참고: 사용 중인 데이터 공급자(MySQL, SQL Server, OleDB 등)는 중요하지 않습니다 . 개념 은 동일합니다.

실시예 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 Dataset 개체가 선언되었지만 인스턴스가 생성되지 않았습니다. DataAdapter 는 생성하지 않고 DataSet 을 채웁니다. 이 경우 ds 는 지역 변수이므로 IDE는 다음 과 같은 일이 발생할 수 있음을 경고합니다.

이미지

모듈/클래스 수준 변수로 선언되면 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)

여기서 오타가 문제입니다: EmployeesEmployee . "Employee"라는 이름의 DataTable 이 생성되지 않았 NullReferenceException 이 액세스를 시도합니다. 또 다른 잠재적인 문제는 SQL에 WHERE 절이 포함될 때 그렇지 않을 수 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

DataAdapterTableNames 를 제공하지만 SQL 또는 데이터베이스 테이블의 이름을 구문 분석하지 않습니다. 결과적으로 ds.Tables("TICKET_RESERVATION") 는 존재하지 않는 테이블을 참조합니다.

해결 방법 은 동일하며 인덱스로 테이블을 참조하십시오.

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

DataTable 클래스 도 참조하십시오.


개체 경로/중첩

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

코드는 Items 만 테스트하고 myFooBar 는 모두 Nothing일 수 있습니다. 해결책 은 한 번에 하나씩 개체의 전체 체인 또는 경로를 테스트하는 것입니다.

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

AndAlso 중요합니다. False 조건이 발생하면 후속 테스트가 수행되지 않습니다. 이렇게 하면 코드가 한 번에 하나의 '레벨' 객체를 안전하게 '드릴'하여 myFoo 가 유효한 것으로 결정된 후에만 myFoo.Bar 복잡한 객체를 코딩할 때 객체 체인 또는 경로가 상당히 길어질 수 있습니다.

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

null 개체의 '다운스트림'을 참조할 수 없습니다. 이는 컨트롤에도 적용됩니다.

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

여기서 myWebBrowser 또는 Document 는 Nothing이거나 formfld1 요소가 없을 수 있습니다.


UI 컨트롤

 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)

무엇보다도 이 코드는 사용자가 하나 이상의 UI 컨트롤에서 무언가를 선택하지 않았을 수 있다고 예상하지 않습니다. ListBox1.SelectedItemNothing 일 수 있으므로 ListBox1.SelectedItem.ToString 은 NRE가 됩니다.

치료

데이터를 사용하기 전에 유효성을 검사합니다( Option Strict 및 SQL 매개변수도 사용):

 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

이것은 NRE를 얻는 매우 일반적인 방법입니다. C#에서 코딩 방식에 따라 IDE는 Controls 이 현재 컨텍스트에 존재하지 않거나 "비정적 멤버를 참조할 수 없음"이라고 보고합니다. 따라서 어느 정도 이것은 VB 전용 상황입니다. 또한 실패 캐스케이드를 초래할 수 있기 때문에 복잡합니다.

배열과 컬렉션은 이 방법으로 초기화할 수 없습니다. 이 초기화 코드는 생성자가 Form 또는 Controls 생성하기 전에 실행됩니다. 결과적으로:

  • 목록 및 컬렉션은 단순히 비어 있습니다.
  • 배열에는 Nothing의 5개 요소가 포함됩니다.
  • somevar .Text 속성이 없기 때문에 즉각적인 NRE가 됩니다.

나중에 배열 요소를 참조하면 NRE가 발생합니다. 이상한 버그로 인해 Form_Load 에서 이 작업을 수행하면 IDE에서 예외가 발생했을 때 보고 하지 않을 수 있습니다. 나중에 코드가 배열을 사용하려고 할 때 예외가 나타납니다. 이 "자동 예외"는 이 게시물에 자세히 설명되어 있습니다. 우리의 목적을 위해 핵심은 양식을 만드는 동안 치명적인 일이 발생하면( Sub New 또는 Form Load 이벤트) 예외가 보고되지 않고 코드가 프로시저를 종료하고 양식만 표시한다는 것입니다.

Sub New 또는 Form Load 이벤트의 다른 코드는 NRE 이후에 실행되지 않으므로 다른 많은 항목 이 초기화되지 않은 상태로 남을 수 있습니다.

 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

부분 구제

VB가 경고를 제공하지 않는 것이 이상하지만 해결 방법은 양식 수준에서 컨테이너 를 선언 하지만 컨트롤이 존재할 때 양식 로드 이벤트 핸들러에서 컨테이너를 초기화하는 것입니다. InitializeComponent 호출 이후에 있는 한 Sub New 에서 이 작업을 수행할 수 있습니다.

 ' 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 에서 찾을 수 없습니다. 해당 Panel 또는 GroupBox의 Controls 컬렉션에 있습니다. 컨트롤 이름의 철자가 틀린 경우에도 컨트롤이 반환되지 않습니다( "TeStBox2" ). 이러한 경우 Nothing 저장되지 않으며 참조를 시도하면 NRE가 발생합니다.

찾고 있는 것이 무엇인지 알았으니 이제 쉽게 찾을 수 있을 것입니다. VS는 당신에게 당신의 방식의 오류를 보여줍니다

"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

이것은 IDE가 '모든 경로가 값을 반환하는 것은 아니며 NullReferenceException 이 발생할 수 있습니다 '라는 경고를 표시하는 경우입니다. Exit FunctionReturn Nothing 으로 대체하여 경고를 표시하지 않을 수 있지만 문제가 해결되지는 않습니다. someCondition = False 때 반환을 사용하려고 하면 NRE가 발생합니다.

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

치료

Exit FunctionReturn bList . List Nothing 을 반환하는 것과 다릅니다. 반환된 개체가 Nothing 일 가능성이 있는 경우 사용하기 전에 테스트하세요.

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

잘못 구현된 Try/Catch

잘못 구현된 Try/Catch는 문제가 있는 위치를 숨기고 새로운 문제를 일으킬 수 있습니다.

 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 에서 예외가 발생하는 SQL('mailaddress' 뒤에)에 추가 쉼표가 있습니다. Catch 가 아무 작업도 수행하지 않은 후 Finally 정리를 수행하려고 시도하지만 null DataReader 개체를 Close NullReferenceException 발생합니다.

Catch 블록은 악마의 놀이터입니다. Finally 블록에서 NRE를 얻었는지 당황했습니다. 다른 상황에서 빈 Catch 는 훨씬 더 다운스트림이 엉망이 되어 문제에 대해 잘못된 위치에서 잘못된 항목을 찾는 데 시간을 소비하게 만들 수 있습니다. (위에서 설명한 "조용한 예외"는 동일한 엔터테인먼트 가치를 제공합니다.)

치료

빈 Try/Catch 블록을 사용하지 마십시오. a) 원인을 식별하고 b) 위치를 식별하고 c) 적절한 해결책을 적용할 수 있도록 코드가 충돌하도록 합니다. Try/Catch 블록은 예외를 수정할 수 있는 고유한 자격을 갖춘 사람인 개발자로부터 예외를 숨기기 위한 것이 아닙니다.


DBNull은 Nothing과 동일하지 않습니다.

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

IsDBNull 함수는 값System.DBNull 과 같은지 테스트하는 데 사용됩니다 . MSDN에서:

System.DBNull 값은 Object가 누락되거나 존재하지 않는 데이터를 나타냄을 나타냅니다. DBNull은 변수가 아직 초기화되지 않았음을 나타내는 Nothing과 동일하지 않습니다.

치료

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

이전과 마찬가지로 Nothing에 대해 테스트한 다음 특정 값에 대해 테스트할 수 있습니다.

 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

chkName 이 있는 CheckBox 를 찾을 수 없는 경우(또는 GroupBox 존재하는 경우) chk 는 Nothing이 되고 속성을 참조하려고 하면 예외가 발생합니다.

치료

 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"

dgvBooksAutoGenerateColumns = 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

DataGridViewAllowUserToAddRowsTrue (기본값)이면 맨 아래에 있는 빈/새 행 Cells Nothing 포함됩니다. ToString )를 사용하려는 대부분의 시도는 NRE를 발생시킵니다.

치료

For/Each 루프를 사용하고 IsNewRow 속성을 테스트하여 마지막 행인지 확인합니다. AllowUserToAddRows 가 true인지 여부에 관계없이 작동합니다.

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

For n 루프를 사용하는 경우 행 수를 수정하거나 IsNewRow 가 true일 때 Exit For


My.Settings(StringCollection)

StringCollection My.Settings 의 항목을 사용하려고 하면 처음 사용할 때 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 예외


Community Wiki

또 다른 시나리오는 null 개체를 값 형식 으로 캐스팅하는 경우입니다. 예를 들어 아래 코드:

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

캐스트에 대해 NullReferenceException 이 발생합니다. 위의 샘플에서는 매우 분명해 보이지만 소유하지 않은 일부 코드에서 null 개체가 반환되고 캐스트가 일부 자동 시스템에서 생성되는 더 "늦은 바인딩" 복잡한 시나리오에서 발생할 수 있습니다.

이에 대한 한 가지 예는 Calendar 컨트롤이 있는 이 간단한 ASP.NET 바인딩 조각입니다.

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

여기에서 SelectedDate 는 사실 Calendar DateTime 유형 속성이며 바인딩은 null을 완벽하게 반환할 수 있습니다. 암시적 ASP.NET 생성기는 위의 캐스트 코드와 동일한 코드 조각을 만듭니다. 그리고 이것은 잘 컴파일되는 ASP.NET 생성 코드에 있기 때문에 발견하기 매우 어려운 NullReferenceException


Community Wiki

이는 코드에서 null로 설정된 개체 참조 변수를 사용했음을 의미합니다(즉, 실제 개체 인스턴스를 참조하지 않음).

오류를 방지하려면 null일 수 있는 개체를 사용하기 전에 null에 대해 테스트해야 합니다.

 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 }

Community Wiki

문제의 변수가 아무 것도 가리키지 않음을 의미합니다. 다음과 같이 생성할 수 있습니다.

 SqlConnection connection = null; connection.Open();

connection "을 선언했지만 아무 것도 가리키지 않았기 때문에 오류가 발생합니다. Open "을 호출하려고 하면 해결할 참조가 없고 오류가 발생합니다.

이 오류를 방지하려면:

  1. 객체로 무엇이든 하기 전에 항상 객체를 초기화하십시오.
  2. 객체가 null인지 확실하지 않으면 object == null 확인하십시오.

JetBrains의 ReSharper 도구는 null 참조 오류가 발생할 가능성이 있는 코드의 모든 위치를 식별하여 null 검사를 허용합니다. 이 오류는 버그의 첫 번째 소스인 IMHO입니다.


Community Wiki

시나리오에 관계없이 원인은 .NET에서 항상 동일합니다.

Nothing / null 인 참조 변수를 사용하려고 합니다. 값이 Nothing / null 실제로 힙에 있는 개체의 인스턴스에 대한 참조를 보유하지 않는다는 의미입니다.

변수에 무언가를 할당하지 않았거나, 변수에 할당된 값의 인스턴스를 생성하지 않았거나 Nothing / null Nothing / null 로 설정하는 함수를 호출했습니다.


Community Wiki

이 예외가 발생하는 예는 다음과 같습니다. 무언가를 확인하려고 할 때 이는 null입니다.

예를 들어:

 string testString = null; //Because it doesn't have a value (ie it's null; "Length" cannot do what it needs to do) if (testString.Length == 0) // Throws a nullreferenceexception { //Do something }

위의 코드와 같이 인스턴스화되지 않은 작업을 수행하려고 하면 .NET 런타임에서 NullReferenceException이 발생합니다.

메서드가 전달되는 항목이 null이 아니라고 예상하는 경우 일반적으로 방어 수단으로 throw되는 ArgumentNullException과 비교합니다.

자세한 내용은 C# NullReferenceException 및 Null Parameter 에 있습니다.


Community Wiki

업데이트 C#8.0, 2019: Null 허용 참조 유형

C#8.0에는 nullable 참조 형식nullable이 아닌 참조 형식이 도입되었습니다. 따라서 NullReferenceException 을 방지하려면 nullable 참조 유형만 확인해야 합니다.


참조 유형을 초기화하지 않고 해당 속성 중 하나를 설정하거나 읽으려는 경우 NullReferenceException이 발생 합니다.

예시:

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

변수가 null이 아닌지 확인하여 간단히 이를 피할 수 있습니다.

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

NullReferenceException이 발생하는 이유를 완전히 이해하려면 값 유형 과 [참조 유형][3]의 차이점을 아는 것이 중요합니다.

따라서 값 유형을 처리하는 경우 NullReferenceExceptions가 발생할 수 없습니다. 참조 유형을 다룰 때는 경계해야 합니다!

이름에서 알 수 있듯이 참조 유형만 참조를 보유하거나 문자 그대로 아무 것도 가리킬 수 없습니다(또는 'null'). 값 유형에는 항상 값이 포함됩니다.

참조 유형(이 유형을 확인해야 함):

  • 동적
  • 물체

값 유형(이 유형은 무시해도 됨):

  • 숫자 유형
  • 적분형
  • 부동 소수점 유형
  • 소수
  • 부울
  • 사용자 정의 구조체

Community Wiki

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

여기서 BookCar 는 호환되지 않는 유형입니다. Car Book 으로 변환/시전할 수 없습니다. 이 캐스트가 실패하면 as null 을 반환합니다. mybook 을 사용 NullReferenceException 이 발생합니다.

일반적으로 다음과 같이 캐스트 또는 as

유형 변환이 항상 성공할 것으로 예상하는 경우(즉, 미리 객체가 무엇인지 알고 있는 경우) 캐스트를 사용해야 합니다.

 ComicBook cb = (ComicBook)specificBook;

이 유형의 확실하지만, 특정 유형으로 사용하려고 시도하는 경우, 사용 as :

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

Community Wiki

null 값 참조가 포함된 개체를 사용하고 있습니다. 따라서 null 예외가 발생합니다. 예제에서 문자열 값은 null이고 길이를 확인할 때 예외가 발생했습니다.

예시:

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

예외 오류는 다음과 같습니다.

처리되지 않은 예외:

System.NullReferenceException: 개체 참조가 개체의 인스턴스로 설정되지 않았습니다. Program.Main()에서


Community Wiki

어떤이 발생하는 동안 NullReferenceExceptions을 하고 피하기 위해 접근 / 다른 답변에서 언급 한 이러한 예외를 수정, 많은 프로그래머가 아직 배운 것을 독립적으로 개발하는 동안 같은 예외를 디버깅하는 방법이다.

Visual Studio에서는 Visual Studio Debugger 덕분에 일반적으로 쉽습니다.


먼저 올바른 오류가 포착되는지 확인하십시오 . VS2010에서 'System.NullReferenceException' 중단을 어떻게 허용합니까?를 참조하십시오. 참고 1

그런 다음 디버깅으로 시작(F5) 하거나 [VS 디버거]를 실행 중인 프로세스에 연결 합니다. Debugger.Break 을 사용하는 것이 유용할 수 있으며, 이는 디버거를 시작하라는 메시지를 표시합니다.

이제 NullReferenceException이 발생(또는 처리되지 않음)되면 디버거가 예외가 발생한 행에서 중지됩니다(위에서 설정한 규칙을 기억하십니까?). 때로는 오류를 쉽게 발견할 수 있습니다.

예를 들어 다음 줄에서 예외를 유발할 myString 이 null로 평가되는 경우입니다. 이것은보고 확인할 수 있습니다 조사 식 창 또는 표현식 실행 직접 실행 창을 .

 var x = myString.Trim();

다음과 같은 고급 사례에서는 위의 기술 중 하나(Watch 또는 Immediate Windows)를 사용하여 표현식을 검사하여 str1 이 null인지 또는 str2 가 null인지 확인해야 합니다.

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

예외가 던져가 위치한되었습니다이고,는 널 (null) 값이 어디에 있는지 알아 이유 뒤쪽에 보통 사소한되면 [잘못] 소개 -

예외의 원인을 이해하는 데 필요한 시간을 가지십시오. null 표현식을 검사합니다. 그러한 널 표현식을 초래할 수 있는 이전 표현식을 검사하십시오. 중단점을 추가하고 적절하게 프로그램을 단계별로 실행합니다. 디버거를 사용합니다.


1 Break on Throw가 너무 공격적이고 디버거가 .NET 또는 타사 라이브러리의 NPE에서 중지되는 경우 Break on User-Unhandled 를 사용하여 catch된 예외를 제한할 수 있습니다. 또한 VS2012는 Just My Code 를 도입하여 활성화하는 것이 좋습니다.

내 코드만 활성화하여 디버깅하는 경우 동작이 약간 다릅니다. 내 코드만 활성화하면 디버거가 내 코드 외부에서 발생하고 내 코드를 통과하지 않는 첫 번째 CLR(공용 언어 런타임) 예외를 무시합니다.


Community Wiki

Simon Mourier는 다음과 같은 예를 들었습니다 .

 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<> 인스턴스를 박싱할 때 런타임이 사용하는 특수 규칙 때문에 발생합니다.


Community Wiki

엔터티 프레임워크에서 사용하는 엔터티의 클래스 이름이 웹 양식 코드 숨김 파일의 클래스 이름과 동일한 경우를 추가합니다.

코드 숨김 클래스가 Contact인 웹 양식 Contact.aspx가 있고 엔터티 이름이 Contact라고 가정합니다.

그런 다음 context.SaveChanges()를 호출할 때 다음 코드에서 NullReferenceException이 발생합니다.

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

엔터티와 코드 숨김 클래스가 동일한 네임스페이스에 있을 때 오류가 발생합니다. 이 문제를 해결하려면 Contact.aspx의 엔터티 클래스 또는 코드 숨김 클래스의 이름을 바꿉니다.

이유 아직 이유를 잘 모르겠습니다. 그러나 엔티티 클래스가 System.Web.UI.Page를 확장할 때마다 이 오류가 발생합니다.

토론을 위해 DbContext.saveChanges()의 NullReferenceException을 살펴보십시오.


Community Wiki

이 예외를 받을 수 있는 또 다른 일반적인 경우는 단위 테스트 중에 클래스를 조롱하는 것과 관련이 있습니다. 사용되는 모의 프레임워크에 관계없이 클래스 계층의 모든 적절한 수준이 적절하게 모의되었는지 확인해야 합니다. HttpContext 모든 속성을 모의(mock)해야 합니다.

다소 장황한 예는 " 사용자 정의 AuthorizationAttribute를 테스트할 때 발생하는 NullReferenceException "을 참조하십시오.


Community Wiki

나는 이에 대해 다른 관점을 가지고 있다. 이런 종류의 대답은 "내가 그것을 피하기 위해 무엇을 더 할 수 있습니까? "

예를 들어 MVC 애플리케이션에서 여러 계층 에서 작업할 때 컨트롤러는 비즈니스 운영을 호출하는 서비스가 필요합니다. 이러한 시나리오에서 종속성 주입 컨테이너 는 NullReferenceException 을 피하기 위해 서비스를 초기화하는 데 사용할 수 있습니다. 따라서 null 검사에 대해 걱정할 필요가 없으며 컨트롤러에서 서비스를 항상 싱글톤 또는 프로토타입으로 사용할 수 있는(및 초기화된) 것처럼 호출하기만 하면 됩니다.

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

Community Wiki

"어떻게해야합니까"에 대해 많은 답변이있을 수 있습니다.

개발하는 동안 이러한 오류 조건을 방지하는 보다 "공식적인" 방법은 코드에서 계약에 따라 설계를 적용하는 것입니다. 이것은 개발하는 동안 시스템에 클래스 불변 및/또는 함수/메서드 사전 조건사후 조건 을 설정해야 함을 의미합니다.

즉, 클래스 불변는 정상적인 사용에 위반되지 않습니다 클래스에 일부 제약이있을 것이다 (따라서, 클래스가 일관성없는 상태로받지 않습니다) 확인합니다. 사전 조건 은 함수/메서드에 대한 입력으로 제공된 데이터가 일부 제약 조건 세트를 따라야 하고 절대 위반하지 않아야 함을 의미하고, 사후 조건 은 함수/메서드 출력이 위반 없이 설정된 제약 조건을 다시 따라야 함을 의미합니다. 계약 조건에 따라서 개발 된 시스템 성능을 최대화하기 위해, 릴리스에서 비활성화되는 동안, 디버그 모드에서 실제로 체크 계약에 의해 설계, 버그없는 프로그램을 실행하는 동안 위반해서는 안됩니다.

이렇게 하면 제약 조건 집합을 위반한 결과인 NullReferenceException 사례를 피할 수 있습니다. 예를 들어, X 를 사용하고 나중에 해당 메서드 중 하나를 호출하려고 하고 X 에 null 값이 있으면 NullReferenceException .

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

그러나 메서드 전제 조건으로 "속성 X는 null 값을 가질 수 없음"을 설정하면 앞에서 설명한 시나리오를 방지할 수 있습니다.

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

이러한 이유로 .NET 응용 프로그램에 대한 코드 계약 프로젝트가 있습니다.

또는 주장을 사용하여 계약에 의한 설계를 적용할 수 있습니다.

업데이트: 이 용어는 에펠 프로그래밍 언어의 디자인과 관련하여 Bertrand Meyer에 의해 만들어졌다는 점을 언급할 가치가 있습니다.


Community Wiki

null 개체의 속성에 액세스하려고 하거나 문자열 값이 비어 있고 문자열 메서드에 액세스하려고 할 때 NullReferenceException

예를 들어:

  1. 빈 문자열의 문자열 메서드에 액세스할 때:

     string str = string.Empty; str.ToLower(); // throw null reference exception
  2. null 객체의 속성에 액세스할 때:

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

Community Wiki

TL은, DR : 사용하여 시도 Html.Partial 대신 Renderpage


다음과 같이 View에 Model을 보내 View 내에서 View를 렌더링하려고 할 때 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 내에서 모델이 Null인 것으로 나타났습니다. 내가 그것을 변경할 때까지 :

 @{ 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가 앰퍼샌드와 대괄호를 잘못 읽었기 때문이라고 생각합니다.


Community Wiki

당신은 그것에 대해 무엇을 할 수 있습니까?

null 참조가 무엇이며 디버깅하는 방법을 설명하는 좋은 답변이 많이 있습니다. 그러나 문제를 방지하거나 최소한 쉽게 잡을 수 있는 방법에 대해서는 거의 없습니다.

인수 확인

예를 들어 메서드는 다른 인수를 확인하여 null인지 확인하고 ArgumentNullException 이 정확한 목적을 위해 생성된 예외 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) 와 같은 구문을 사용하는 "Microsoft 코드 계약"이 있습니다. 코드 계약 소개 .

다음과 같은 속성만 사용할 수 있는 "PostSharp"도 있습니다.

 public void DoSometing([NotNull] obj)

그렇게 하고 PostSharp를 빌드 프로세스의 일부로 만들면 obj 가 null인지 확인됩니다. 참조: PostSharp null 확인

일반 코드 솔루션

또는 항상 기존 코드를 사용하여 고유한 접근 방식을 코딩할 수 있습니다. 예를 들어 다음은 null 참조를 잡는 데 사용할 수 있는 구조체입니다. 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 로 또는 T에서 캐스트되므로 필요한 거의 모든 곳에서 사용할 수 있습니다. 예를 들어 NotNull<Person> 을 사용하는 메서드에 Person 개체를 전달할 수 있습니다.

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

nullable과 마찬가지로 위에서 볼 수 있듯이 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();

깃허브

참고로 위의 코드를 GitHub에서 사용할 수 있도록 만들었습니다. 다음 위치에서 찾을 수 있습니다.

https://github.com/luisperezphd/NotNull

관련 언어 기능

C# 6.0은 이것을 조금 도와주는 "null-conditional operator"를 도입했습니다. 이 기능을 사용하면 중첩된 개체를 참조할 수 있으며 그 중 하나가 null 이면 전체 표현식이 null 반환합니다.

이렇게 하면 경우에 따라 수행해야 하는 null 검사 수가 줄어듭니다. 구문은 각 점 앞에 물음표를 넣는 것입니다. 다음 코드를 예로 들어 보겠습니다.

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

country State 등의 속성을 가진 Country 유형의 개체라고 상상해 보십시오. country , State , County 또는 City null 이면 address will be null이 . Therefore you only have to check whether 따라서 주소 is null` . Therefore you only have to check whether

훌륭한 기능이지만 정보를 덜 제공합니다. 4 중 어느 것이 null인지 명확하지 않습니다.

Nullable과 같은 내장?

Nullable<T> 대한 멋진 속기가 있습니다. so int? .

C#에 NotNull<T> 구조체와 같은 것이 있고 비슷한 속기, 느낌표(!)가 있으면 다음과 같이 작성할 수 있으면 public void WriteName(Person! person) .


Community Wiki

C# 6에서 Null 조건부 연산자를 사용하여 NullReferenceException을 깔끔하게 수정하고 null 검사를 처리하는 코드를 적게 작성할 수 있습니다.

멤버 액세스(?.) 또는 인덱스(?[) 작업을 수행하기 전에 null을 테스트하는 데 사용됩니다.

예시

 var name = p?.Spouse?.FirstName;

다음과 같습니다.

 if (p != null) { if (p.Spouse != null) { name = p.Spouse.FirstName; } }

결과는 p가 null이거나 p.Spouse가 null일 때 이름이 null이 된다는 것입니다.

그렇지 않으면 변수 이름에 p.Spouse.FirstName 값이 할당됩니다.

: 자세한 내용은 널 조건 연산자


Community Wiki

흥미롭게도 이 페이지의 답변 중 두 가지 극단적인 경우를 언급하지 않습니다.

엣지 케이스 #1: 사전에 동시 액세스

.NET의 일반 사전은 스레드로부터 안전하지 않으며 두 개의 동시 스레드에서 키에 액세스하려고 할 때 때때로 NullReference 또는 심지어 (더 자주) KeyNotFoundException 이 경우 예외는 매우 오해의 소지가 있습니다.

엣지 케이스 #2: 안전하지 않은 코드

unsafe NullReferenceException 이 발생하면 포인터 변수를 보고 IntPtr.Zero 또는 기타 항목이 있는지 확인할 수 있습니다. 이것은 같은 것입니다("널 포인터 예외"). 그러나 안전하지 않은 코드에서 변수는 종종 값 유형/배열 등으로 캐스트되고, 값 유형이 어떻게 이것을 던질 수 있는지 궁금해하면서 벽에 머리를 부딪칩니다. 예외.

(그런데 필요한 경우가 아니면 안전하지 않은 코드를 사용하지 않는 또 다른 이유입니다.)

에지 케이스 #3: 기본 모니터와 DPI 설정이 다른 보조 모니터로 Visual Studio 다중 모니터 설정

이 엣지 케이스는 소프트웨어에 따라 다르며 Visual Studio 2019 IDE(및 이전 버전도 가능)와 관련이 있습니다.

문제를 재현하는 방법: 도구 상자에서 기본 모니터와 다른 DPI 설정을 사용하여 기본이 아닌 모니터의 Windows 양식으로 구성 요소를 드래그하면 "개체 참조가 인스턴스로 설정되지 않음" 팝업이 나타납니다. 물체." 이 스레드 에 따르면 이 문제는 꽤 오랫동안 알려졌으며 작성 당시에도 여전히 수정되지 않았습니다.


Community Wiki

오류 줄 "개체 참조가 개체의 인스턴스로 설정되지 않았습니다." 개체 참조에 인스턴스 개체를 할당하지 않았으며 여전히 해당 개체의 속성/메서드에 액세스하고 있음을 나타냅니다.

예를 들어 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 an error } }

myClass 클래스의 참조가 선언되었지만 인스턴스화되지 않았거나 개체의 인스턴스가 해당 클래스의 참조에 할당되지 않았기 때문에 위의 행에서 오류가 발생합니다.

이 문제를 해결하려면 인스턴스화해야 합니다(객체를 해당 클래스의 참조에 할당).

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

Community Wiki

NullReferenceException 또는 개체 참조가 개체의 인스턴스로 설정되지 않은 것은 사용하려는 클래스의 개체가 인스턴스화되지 않은 경우 발생합니다. 예를 들어:

Student라는 클래스가 있다고 가정합니다.

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

위의 코드에서 볼 수 있듯이 Student s - 문은 Student 유형의 변수만 선언합니다. 이 시점에서 Student 클래스는 인스턴스화되지 않습니다. 따라서 s.GetFullName() 문이 실행되면 NullReferenceException이 발생합니다.


Community Wiki

음, 간단히 말해서:

생성되지 않았거나 현재 메모리에 없는 개체에 액세스하려고 합니다.

따라서 이를 해결하는 방법은 다음과 같습니다.

  1. 디버그하고 디버거를 중단시키십시오... 중단된 변수로 직접 이동합니다... 이제 귀하의 작업은 단순히 이 문제를 해결하는 것입니다. 적절한 위치에 new 키워드를 사용하십시오.

  2. 개체가 없기 때문에 일부 데이터베이스 명령에서 발생하는 경우 null 검사를 수행하고 처리하기만 하면 됩니다.

     if (i == null) { // Handle this }
  3. 가장 어려운 것 .. GC 가 객체를 이미 수집했다면 ... 이것은 일반적으로 문자열을 사용하여 객체를 찾으려고 할 때 발생합니다 ... 즉, 객체의 이름으로 찾는 경우 GC가 이미 발생할 수 있습니다. 정리했습니다... 이것은 찾기 어렵고 상당히 문제가 될 것입니다... 이 문제를 해결하는 더 좋은 방법은 개발 프로세스 중에 필요한 곳에서 null 검사를 수행하는 것입니다. 이렇게 하면 많은 시간을 절약할 수 있습니다.

이름으로 찾기란 일부 프레임워크에서 문자열을 사용하여 FIndObjects를 찾을 수 있도록 하며 코드는 다음과 같을 수 있음을 의미합니다. FindObject("ObjectName");


Community Wiki

말 그대로 NullReferenceExeption을 수정하는 가장 쉬운 방법에는 두 가지 방법이 있습니다.

예를 들어 스크립트가 첨부된 GameObject가 있고 rb (rigidbody)라는 변수가 있는 경우 이 변수는 게임을 시작할 때 null로 시작합니다. 이것이 컴퓨터에 해당 변수에 저장된 데이터가 없기 때문에 NullReferenceExeption이 발생하는 이유입니다.

RigidBody 변수를 예로 사용하겠습니다. 실제로 몇 가지 방법으로 데이터를 정말 쉽게 추가할 수 있습니다.

  1. AddComponent > Physics > Rigidbody를 사용하여 개체에 RigidBody를 추가한 다음 스크립트로 이동하여 rb = GetComponent<Rigidbody>(); 이 코드 줄은 Start() 또는 Awake() 함수에서 가장 잘 작동합니다.
  2. 프로그래밍 방식으로 구성 요소를 추가하고 한 줄의 코드로 동시에 변수를 할당할 수 있습니다. rb = AddComponent<RigidBody>();

또한 참고 : 당신이 원하는 경우 유니티 개체에 구성 요소를 추가하고 당신이 하나를 추가 할 수 잊어 버린 수, 당신은 입력 할 수 있습니다 [RequireComponent(typeof(RigidBody))] 클래스 선언 (사용자의 사용의 모든 아래 공간) 위.

즐기고 재미있게 게임을 만드십시오!


Community Wiki

빌드를 저장하거나 컴파일하는 동안 이 메시지가 표시되면 모든 파일을 닫고 컴파일하고 저장할 파일을 여십시오.

나에게 그 이유는 파일의 이름을 바꾸고 이전 파일이 여전히 열려 있었기 때문입니다.


Community Wiki

이것은 기본적으로 Null 참조 예외 입니다. 마이크로소프트가 말했듯이-

값이 null인 형식의 멤버에 액세스하려고 하면 NullReferenceException 예외가 throw됩니다.

그게 무슨 뜻이야?

즉, 가치가 없는 구성원이 특정 작업을 수행하도록 하는 경우 시스템은 의심할 여지 없이 메시지를 던지고 다음과 같이 말합니다.

"잠깐만요, 그 멤버는 가치가 없어서 당신이 넘겨준 작업을 수행할 수 없습니다."

예외 자체는 무언가가 참조되고 있지만 값이 설정되지 않는다고 말합니다. 따라서 이것은 참조 유형을 사용하는 동안에만 발생함을 나타냅니다. 값 유형이 null을 허용하지 않기 때문입니다.

Value 형식 멤버를 사용하는 경우 NullReferenceException이 발생하지 않습니다.

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

위의 코드는 null 값이 할당된 간단한 문자열을 보여줍니다.

지금, 나는이 str 문자열의 길이를 인쇄 할 때, 나는 'System.NullReferenceException'형식의 처리되지 않은 예외를받을 수 있나요 회원 STR가 null을 가리키는 때문에 메시지가 발생하고 널의 길이있을 수 없다.

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

위 코드의 컴파일러는 변수 obj 가 할당되지 않았다는 오류를 발생시키며 이는 변수에 null 값이 있거나 아무것도 없음을 나타냅니다. 위 코드의 컴파일러는 변수 obj 가 할당되지 않았다는 오류를 발생시키며 이는 변수에 null 값이 있거나 아무것도 없음을 나타냅니다.

왜 발생합니까?

  • NullReferenceException은 객체의 값을 확인하지 않은 우리의 잘못으로 인해 발생합니다. 우리는 종종 코드 개발에서 객체 값을 선택하지 않은 상태로 둡니다.

  • 객체를 인스턴스화하는 것을 잊었을 때도 발생합니다. null 값을 반환하거나 설정할 수 있는 메서드, 속성, 컬렉션 등을 사용하는 것도 이 예외의 원인이 될 수 있습니다.

어떻게 피할 수 있습니까?

이 유명한 예외를 피하는 다양한 방법과 방법이 있습니다.

  1. 명시적 검사: 객체, 속성, 메서드, 배열 및 컬렉션이 null인지 확인하는 전통을 따라야 합니다. 이것은 if-else if-else 등과 같은 조건문을 사용하여 간단히 구현할 수 있습니다.

  2. 예외 처리: 이 예외를 관리하는 중요한 방법 중 하나입니다. 간단한 try-catch-finally 블록을 사용하여 이 예외를 제어하고 로그를 유지할 수도 있습니다. 이것은 애플리케이션이 프로덕션 단계에 있을 때 매우 유용할 수 있습니다.

  3. Null 연산자: Null 병합 연산자 및 null 조건부 연산자는 개체, 변수, 속성 및 필드에 값을 설정하는 동안에도 편리하게 사용할 수 있습니다.

  4. 디버거: 개발자에게는 디버깅이라는 큰 무기가 있습니다. 개발 단계에서 NullReferenceException에 직면한 경우 디버거를 사용하여 예외의 소스에 도달할 수 있습니다.

  5. 기본 제공 메서드: GetValueOrDefault(), IsNullOrWhiteSpace() 및 IsNullorEmpty()와 같은 시스템 메서드는 null을 확인하고 null 값이 있는 경우 기본값을 할당합니다.

여기에 이미 좋은 답변이 많이 있습니다. 내 블로그 에서 예제 와 함께 더 자세한 설명 을 확인할 수도 있습니다 .

이것도 도움이 되길 바랍니다!


Community Wiki

출처 : http:www.stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it

반응형