나는 약간의 코드를 가지고 있으며 실행될 때,을 던진다 NullReferenceException
.
객체 참조가 객체의 인스턴스로 설정되지 않았습니다.
이것은 무엇을 의미하며이 오류를 해결하기 위해 무엇을 할 수 있습니까?
나는 약간의 코드를 가지고 있으며 실행될 때,을 던진다 NullReferenceException
.
객체 참조가 객체의 인스턴스로 설정되지 않았습니다.
이것은 무엇을 의미하며이 오류를 해결하기 위해 무엇을 할 수 있습니까?
답변:
당신은 뭔가 사용하려는 null
(또는 Nothing
VB.NET에서 참조). 즉,로 설정 null
했거나 전혀 설정하지 않았습니다.
다른 것과 마찬가지로, null
전달됩니다. 이 경우 null
에 방법 "A", 그 방법 "B"가 전달 될 수 null
에 방법 "A".
null
다른 의미를 가질 수 있습니다 :
NullReferenceException
.null
있습니다. C #에는 변수에 대한 널 입력 가능 데이터 유형 개념이 있습니다 (데이터베이스 테이블에 널 입력 가능 필드가있을 수 있음). null
예를 들어 int? a = null;
물음표에 널 저장 가능 변수 a
. 당신은 함께 그 중 하나를 확인할 수 있습니다 if (a.HasValue) {...}
또는 함께 if (a==null) {...}
. a
이 예제 와 같이 널 입력 가능 변수 를 통해 a.Value
명시 적으로 또는 일반 via를 통해 값에 액세스 할 수 있습니다 a
. a.Value
발생 InvalidOperationException
대신에 (A)의 NullReferenceException
경우 a
IS를null
-사전에 확인을 수행해야합니다. 즉, 다른 널 입력 가능 변수 int b;
가있는 if (a.HasValue) { b = a.Value; }
경우 더 작거나 같은 지정을 수행해야합니다 if (a != null) { b = a; }
.이 기사의 나머지 부분은 더 자세하게 설명하고 많은 프로그래머가 종종 실수를 일으켜 실수를 일으킨다 NullReferenceException
.
runtime
A가 던지는 NullReferenceException
항상 당신이 참조를 사용하려고하고 참조가 초기화되지 않습니다 (또는이되었다 같은 일을 의미 한 번 초기화되지만, 더 이상 초기화 없음).
이는 참조가 null
이며 null
참조를 통해 멤버 (예 : 메소드)에 액세스 할 수 없음을 의미합니다 . 가장 간단한 경우 :
string foo = null;
foo.ToUpper();
를 가리키는 참조 NullReferenceException
에서 인스턴스 메소드 ToUpper()
를 호출 할 수 없기 때문에 두 번째 행 에가 표시 string
됩니다 null
.
의 출처를 어떻게 찾을 수 NullReferenceException
있습니까? 그 외에도이 발생하는 위치에 정확하게 던져 질 것이다 제외하고 자체보고에서, Visual Studio에서 디버깅의 일반 규칙이 적용 장소 전략적 중단 점 및 귀하의 변수를 검사 , 중 하나 (개방, 자신의 이름 위에 마우스를 가져 가면 빨리보기) 또는 지역 및 자동차와 같은 다양한 디버깅 패널을 사용하십시오.
참조가 설정되었거나 설정되지 않은 위치를 찾으려면 해당 이름을 마우스 오른쪽 단추로 클릭하고 "모든 참조 찾기"를 선택하십시오. 그런 다음 발견 된 모든 위치에 중단 점을 배치하고 디버거가 연결된 상태에서 프로그램을 실행할 수 있습니다. 디버거가 이러한 중단 점에서 중단 될 때마다 참조가 널이 아닌 것으로 예상되는지 판별하고 변수를 검사하여 예상시 인스턴스를 가리키는 지 확인해야합니다.
이 방법으로 프로그램 흐름을 따르면 인스턴스가 null이 아니어야하는 위치와 제대로 설정되지 않은 이유를 찾을 수 있습니다.
예외가 발생할 수있는 몇 가지 일반적인 시나리오 :
ref1.ref2.ref3.member
ref1 또는 ref2 또는 ref3이 null이면을 얻습니다 NullReferenceException
. 문제를 해결하려면 식을 더 간단한 것으로 다시 작성하여 널 중 하나를 찾으십시오.
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) 널 참조를 피하려면 상위 (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.
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
}
}
###Bad Naming Conventions:
If you named fields differently from locals, you might have realized that you never initialized the field.
공개 클래스 Form1 {개인 고객 고객;
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;
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!";
}
}
// if the "FirstName" session value has not yet been set,
// then this line will throw a NullReferenceException
string firstName = Session["FirstName"].ToString();
@Model
에서의 속성을 참조 할 때 예외가 발생하면 뷰를 볼 때 작업 메소드에서 가져 오기가 설정되어 ASP.NET MVC View
있음을 이해해야합니다 . 컨트롤러에서 빈 모델 (또는 모델 속성)을 반환하면 뷰가 액세스 할 때 예외가 발생합니다.Model
return
// Controller
public class Restaurant:Controller
{
public ActionResult Search()
{
return View(); // Forgot the provide a Model here.
}
}
// Razor view
@foreach (var restaurantSearch in Model.RestaurantSearch) // Throws.
{
}
<p>@Model.somePropertyName</p> <!-- Also throws -->
WPF
컨트롤은 호출하는 동안 InitializeComponent
시각적 트리에 나타나는 순서대로 만들어 집니다. (A)는 NullReferenceException
화재시 등 이벤트 핸들러, 조기 만든 컨트롤의 경우에 발생합니다 InitializeComponent
늦게 생성 된 컨트롤을 참조한다.
예를 들면 다음과 같습니다.
<Grid>
<!-- Combobox declared first -->
<ComboBox Name="comboBox1"
Margin="10"
SelectedIndex="0"
SelectionChanged="comboBox1_SelectionChanged">
<ComboBoxItem Content="Item 1" />
<ComboBoxItem Content="Item 2" />
<ComboBoxItem Content="Item 3" />
</ComboBox>
<!-- Label declared later -->
<Label Name="label1"
Content="Label"
Margin="10" />
</Grid>
여기에 comboBox1
이전에 생성됩니다 label1
. 경우 comboBox1_SelectionChanged
기준 'LABEL1을 시도, 그것은 아직 생성되지 않았을 것입니다.
private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
label1.Content = comboBox1.SelectedIndex.ToString(); // NullReference here!!
}
디자인 철학의 문제를 무시하고 ( 이전 에 XAML
목록을 작성 하여) 선언의 순서를 변경하면 적어도 여기 에서 해결 됩니다.label1
comboBox1
NullReferenceException
as
var myThing = someObject as Thing;
이것은 던지지 InvalidCastException
않지만 null
캐스트가 실패 할 때 (그리고 someObject
자체가 null 일 때 )를 반환합니다 . 그러니 알아 두십시오.
FirstOrDefault()
와SingleOrDefault()
아무것도없는 경우 일반 버전 First()
과 Single()
예외가 발생합니다. 이 경우 "OrDefault"버전은 null을 반환합니다. 그러니 알아 두십시오.
foreach
null 수집을 반복하려고 할 때 발생합니다. 일반적으로 null
컬렉션을 반환하는 메서드에서 예기치 않은 결과가 발생합니다 .
List<int> list = null;
foreach(var v in list) { } // exception
보다 현실적인 예-XML 문서에서 노드를 선택하십시오. 노드를 찾을 수 없지만 초기 디버깅에서 모든 속성이 유효한 것으로 표시되면 throw됩니다.
foreach (var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))
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
메소드 호출에서 명시 적으로 확인 하고 사용자 정의 예외를 발생시킵니다.호출 코드에서 예외를 잡기 위해 사용자 정의 예외를 던질 수도 있습니다.
string GetCategory(string bookTitle)
{
var book = library.FindBook(bookTitle); // This may return null
if (book == null)
throw new BookNotFoundException(bookTitle); // Your custom exception
return book.Category;
}
Debug.Assert
값이되어서는 안 경우 null
문제 이전에 예외가 발생보다 잡으려고.개발 중에 메서드가 반환 null
할 수 는 있지만 반환해서는 안된다는 것을 알고있는 경우, 메서드 Debug.Assert()
가 발생할 때 가능한 빨리 중단 하는 데 사용할 수 있습니다.
string GetTitle(int knownBookID)
{
// You know this should never return null.
var book = library.GetBook(knownBookID);
// Exception will occur on the next line instead of at the end of this method.
Debug.Assert(book != null, "Library didn't return a book for known book ID.");
// Some other code
return book.Title; // Will never throw NullReferenceException in Debug mode.
}
이 검사는 비록 당신의 릴리스 빌드에서 생을 마감하지 않습니다 는 던져 원인이 NullReferenceException
때 다시 book == null
릴리스 모드에서 실행시.
GetValueOrDefault()
을위한 nullable
그들이 때 값 형식은 기본값을 제공합니다 null
.DateTime? appointment = null;
Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now));
// Will display the default value provided (DateTime.Now), because appointment is null.
appointment = new DateTime(2022, 10, 20);
Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now));
// Will display the appointment date, not the default
??
[C #] 또는 If()
[VB]를 사용하십시오.a 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;
}
?.
하거나 ?[x]
배열에 사용하십시오 (C # 6 및 VB.NET 14에서 사용 가능).이것을 안전한 네비게이션 또는 엘비스 (모양 후) 연산자라고도합니다. 연산자의 왼쪽에있는 표현식이 널이면 오른쪽이 평가되지 않고 대신 널이 리턴됩니다. 이는 다음과 같은 경우를 의미합니다.
var title = person.Title.ToUpper();
사람에게 제목이 없으면 ToUpper
null 값을 가진 속성 을 호출하려고하기 때문에 예외가 발생 합니다.
년 C# 5
이하, 이것은으로 보호 할 수 있습니다 :
var title = person.Title == null ? null : person.Title.ToUpper();
이제 제목 변수는 예외를 던지는 대신 null이됩니다. C # 6은 이에 대한 짧은 구문을 소개합니다.
var title = person.Title?.ToUpper();
이 제목 변수의 존재가 발생합니다 null
, 그리고 호출하는 ToUpper
경우 제작되지 않은 person.Title
것입니다 null
.
물론 기본값을 제공 하려면 여전히title
null 을 확인 하거나 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");
이 작업은 다음을 수행합니다. myIntArray
null 인 경우 표현식은 null을 반환하므로 안전하게 확인할 수 있습니다. 배열이 포함 된 경우 : elem = myIntArray[i];
와 동일하게 수행
되며 i<sup>th</sup>
요소를 반환합니다 .
C# 8
null 컨텍스트 및 nullable 참조 유형에 소개되어 변수에 대한 정적 분석을 수행하고 값이 null이거나 null로 설정된 경우 컴파일러 경고를 제공합니다. 널 입력 가능 참조 유형을 사용하면 유형을 명시 적으로 널로 허용 할 수 있습니다.
파일 의 Nullable
요소를 사용하여 프로젝트에 대해 널 입력 가능 주석 컨텍스트 및 널 입력 가능 경고 컨텍스트를 설정할 수 있습니다 csproj
. 이 요소는 컴파일러가 형식의 null 허용 여부를 해석하는 방법과 생성되는 경고를 구성합니다. 유효한 설정은 다음과 같습니다.
널 입력 가능 참조 유형은 널 입력 가능 값 유형과 동일한 구문을 사용하여 표시됩니다. a ?
는 변수 유형에 추가됩니다.
C#
"반복자 블록"(일부 인기있는 다른 언어에서는 "생성기"라고 함)을 지원합니다. Null 역 참조 예외는 지연된 실행으로 인해 반복기 블록에서 디버그하기가 특히 까다로울 수 있습니다.
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 검사를 작성하면 null 역 참조를 방지 할 수 있지만 null 인수 예외를 호출 지점이 아닌 반복 지점으로 이동하면 디버그하기 가 매우 복잡합니다 .
올바른 수정 사항은 다음과 같습니다.
// 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();
}
즉, 반복자 블록 논리가있는 개인 헬퍼 메소드와 널 점검을 수행하고 반복자를 리턴하는 공용 표면 메소드를 작성하십시오. 이제 GetFrobs
호출되면 null 검사가 즉시 GetFrobsForReal
수행 된 다음 시퀀스가 반복 될 때 실행됩니다.
LINQ
Objects에 대한 참조 소스를 살펴보면 이 기술이 전체적으로 사용되는 것을 볼 수 있습니다. 작성하는 것이 약간 더 복잡하지만 nullity 오류 디버깅이 훨씬 쉽습니다. 작성자의 편의가 아닌 발신자의 편의를 위해 코드를 최적화하십시오 .
C#
"안전하지 않은"모드는 이름에서 알 수 있듯이 메모리 안전 및 유형 안전을 제공하는 일반적인 안전 메커니즘이 적용되지 않기 때문에 매우 위험합니다. 메모리 작동 방식을 철저하고 깊이 이해하지 않으면 안전하지 않은 코드를 작성해서는 안됩니다 .
안전하지 않은 모드에서는 다음 두 가지 중요한 사실을 알고 있어야합니다.
그 이유를 이해하려면 .NET이 우선 null 역 참조 예외를 생성하는 방법을 이해하는 데 도움이됩니다. (이 세부 사항은 Windows에서 실행되는 .NET에 적용되며 다른 운영 체제에서도 유사한 메커니즘을 사용합니다.)
메모리는 다음과 같이 가상화됩니다 Windows
. 각 프로세스는 운영 체제에서 추적하는 많은 "페이지"메모리의 가상 메모리 공간을 확보합니다. 각 메모리 페이지에는 읽기, 쓰기, 실행 등의 사용 방법을 결정하는 플래그가 설정되어 있습니다. 가장 낮은 페이지는 "만약 과거의 어떤 방식으로 사용 오류가 발생"으로 표시됩니다.
널 포인터와 널 참조 C#
는 내부적으로 숫자 0으로 표시되므로이를 해당 메모리 저장 영역으로 역 참조하려고하면 운영 체제에서 오류가 발생합니다. 그런 다음 .NET 런타임은이 오류를 감지하여 널 역 참조 예외로 바꿉니다.
따라서 널 포인터와 널 참조를 모두 역 참조하면 동일한 예외가 발생합니다.
두 번째 요점은 어떻습니까? 가상 메모리의 가장 낮은 페이지에 있는 유효하지 않은 포인터를 참조 하면 동일한 운영 체제 오류가 발생하여 동일한 예외가 발생합니다.
왜 이것이 의미가 있습니까? 두 개의 int를 포함하는 구조체와 null과 같은 관리되지 않는 포인터가 있다고 가정 해보십시오. 구조체에서 두 번째 int를 역 참조 CLR
하려고하면 위치 0에서 저장소에 액세스하려고 시도하지 않습니다. 위치 4의 스토리지에 액세스합니다. 그러나 논리적으로 이것은 null을 통해 해당 주소에 도달하기 때문에 null 역 참조 입니다.
안전하지 않은 코드로 작업하고 null 역 참조 예외가 발생하는 경우 문제가되는 포인터가 null 일 필요는 없습니다. 가장 낮은 페이지의 어느 위치 에나있을 수 있으며이 예외가 발생합니다.
그만큼 NullReference Exception
for Visual Basic 은 C # for 와 다릅니다 . 결국 둘 다 .NET Framework에 정의 된 것과 동일한 예외를보고합니다. Visual Basic에 고유 한 원인은 거의 없습니다 (아마도 하나만).
이 답변은 Visual Basic 용어, 구문 및 컨텍스트를 사용합니다. 사용 된 예제는 과거의 많은 스택 오버플로 질문에서 비롯된 것입니다. 이는 다음을 사용하여 관련성을 극대화하기위한 것입니다. 종류의 자주 게시물에서 볼 상황을. 그것을 필요로하는 사람들을위한 약간의 설명도 제공됩니다. 당신과 비슷한 예가되어 매우 가능성이 여기에 나열된.
노트 :
NullReferenceException
NRE의 원인, 찾는 방법, 해결 방법 및 피하는 방법을 이해하는 데 도움이 됩니다. NRE는 여러 가지 방법으로 발생할 수 있으므로 이것이 유일한 만남은 아닐 것입니다."개체가 개체의 인스턴스로 설정되지 않았습니다" 라는 메시지 는 초기화되지 않은 개체를 사용하려고 함을 나타냅니다. 이것은 다음 중 하나로 요약됩니다.
문제는 객체 참조이기 때문에 Nothing
답은 어떤 것을 찾는 지 알아 보는 것입니다. 그런 다음 초기화되지 않은 이유를 판별하십시오. 다양한 변수 위에 마우스를 대면 Visual Studio (VS)에 값이 표시됩니다 Nothing
. 원인은입니다 .
또한 관련 코드, 특히 Catch 블록에 아무것도없는 Try / Catch 블록을 제거해야합니다. 그러면 객체를 사용하려고 할 때 코드가 중단됩니다 Nothing
. 이것은 문제 의 정확한 위치 를 식별 하고 문제를 일으키는 개체를 식별 할 수 있기 때문에 원하는 것입니다.
MsgBox
캐치에 표시되는 A Error while...
는 거의 도움이되지 않습니다. 이 방법은 또한 매우 나쁜 실제 예외, 관련된 객체 또는 발생하는 코드 라인을 설명 할 수 없기 때문에 스택 오버플로 질문으로 집니다.
당신은 또한 사용할 수 있습니다 Locals Window
( > 지방 주민 - -> 윈도우 디버그 개체를 검사).
문제의 위치와 위치를 알고 나면 새 질문을 게시하는 것보다 수정하기가 쉽고 빠릅니다.
또한보십시오:
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
참고 : 생성자 ( )를 포함하여 프로 시저에서 다시 사용 하지 마십시오 .Dim
Sub New
Private reg As CashRegister
'...
Public Sub New()
'...
Dim reg As New CashRegister
End Sub
그러면 해당 컨텍스트 (sub)에만 존재 하는 로컬 변수 가 생성됩니다 reg
. 다른 곳에서 사용할 reg
모듈 수준 의 변수는 Scope
그대로 유지 Nothing
됩니다.
New
연산자가 누락 된 원인은 # 1입니다.NullReference Exceptions
검토 된 스택 오버플로 질문에서 가장 큰 .Visual Basic의 프로세스가 사용하여 반복적으로 명확하게하려고
New
다음 사용New
운영자 것은 만들어 새로운 객체와 통화Sub New
- 생성자 - 개체가 다른 초기화를 수행 할 수 있습니다.
명확히하기 위해 Dim
(또는 Private
) 변수와 변수 만 선언 합니다 Type
. 변수 의 범위 ( 전체 모듈 / 클래스에 존재하는지 또는 프로 시저에 로컬인지) 는 선언 된 위치에 따라 결정됩니다 . Scope가Private | Friend | Public
아닌 액세스 레벨을 정의합니다 .
자세한 내용은 다음을 참조하십시오.
배열도 인스턴스화해야합니다.
Private arr as String()
이 배열은 선언되지 않았으며 생성되지 않았습니다. 배열을 초기화하는 방법에는 여러 가지가 있습니다.
Private arr as String() = New String(10){}
' or
Private arr() As String = New String(10){}
' For a local array (in a procedure) and using 'Option Infer':
Dim arr = New String(10) {}
참고 : 문자를 사용하여 로컬 배열을 초기화 할 때 VS 2010부터 Option Infer
의 As <Type>
및 New
요소는 선택 사항입니다 :
Dim myDbl As Double() = {1.5, 2, 9.9, 18, 3.14}
Dim myDbl = New Double() {1.5, 2, 9.9, 18, 3.14}
Dim myDbl() = {1.5, 2, 9.9, 18, 3.14}
데이터 유형 및 배열 크기는 할당되는 데이터에서 유추됩니다. 클래스 / 모듈 레벨 선언에는 여전히 다음이 필요 As <Type>
합니다 Option Strict
.
Private myDoubles As Double() = {1.5, 2, 9.9, 18, 3.14}
예 : 클래스 객체의 배열
Dim arrFoo(5) As Foo
For i As Integer = 0 To arrFoo.Count - 1
arrFoo(i).Bar = i * 10 ' Exception
Next
배열이 작성되었지만 그 Foo
안에 있는 오브젝트는 작성 되지 않았습니다.
치료제
For i As Integer = 0 To arrFoo.Count - 1
arrFoo(i) = New Foo() ' Create Foo instance
arrFoo(i).Bar = i * 10
Next
를 사용하면 List(Of T)
유효한 객체가없는 요소를 갖는 것이 매우 어렵습니다.
Dim FooList As New List(Of Foo) ' List created, but it is empty
Dim f As Foo ' Temporary variable for the loop
For i As Integer = 0 To 5
f = New Foo() ' Foo instance created
f.Bar = i * 10
FooList.Add(f) ' Foo object added to list
Next
자세한 내용은 다음을 참조하십시오.
.NET 컬렉션 (목록, 사전 등 다양한 종류가 있음)도 인스턴스화하거나 만들어야합니다.
Private myList As List(Of String)
..
myList.Add("ziggy") ' NullReference
같은 이유로 같은 예외가 발생합니다- myList
선언되었지만 인스턴스가 생성되지 않았습니다. 해결책은 동일합니다.
myList = New List(Of String)
' Or create an instance when declared:
Private myList As New List(Of String)
일반적인 감독은 컬렉션을 사용하는 클래스입니다 Type
.
Public Class Foo
Private barList As List(Of Bar)
Friend Function BarCount As Integer
Return barList.Count
End Function
Friend Sub AddItem(newBar As Bar)
If barList.Contains(newBar) = False Then
barList.Add(newBar)
End If
End Function
barList
선언 된 것이 아니라 인스턴스화되지 않았기 때문에 두 프로 시저 중 하나가 NRE 가됩니다. 의 인스턴스를 만들면 Foo
내부의 인스턴스도 만들어지지 않습니다 barList
. 생성자 에서이 작업을 수행하려는 의도 일 수 있습니다.
Public Sub New ' Constructor
' Stuff to do when a new Foo is created...
barList = New List(Of Bar)
End Sub
이전과 같이 이것은 올바르지 않습니다.
Public Sub New()
' Creates another barList local to this procedure
Dim barList As New List(Of Bar)
End Sub
자세한 내용은 List(Of T)
클래스를 참조하십시오 .
NullReference에 대한 데이터베이스를 선물로 많은 기회를 작업 많은 개체 (이있을 수 있기 때문에 Command
, Connection
, Transaction
, Dataset
, DataTable
, DataRows
한 번에 사용 ....). 참고 : 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)
오타 여기에 문제가 : Employees
대 Employee
. DataTable
"직원"이라는 이름의 이름 이 작성되지 않았 으므로 NullReferenceException
결과에 액세스하려고했습니다. 또 다른 잠재적 인 문제는 Items
SQL에 WHERE 절이 포함되어 있지 않을 수도 있다는 가정 입니다.
치료제
이것은 하나의 테이블을 사용 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
위의 예와 같이 DataAdapter
제공 TableNames
되지만 SQL 또는 데이터베이스 테이블의 이름은 구문 분석하지 않습니다. 결과적으로ds.Tables("TICKET_RESERVATION")
으로 존재하지 않는 테이블을 참조합니다.
해결책 인덱스 테이블을 참조 동일하다 :
If ds.Tables(0).Rows.Count > 0 Then
DataTable 클래스 도 참조하십시오 .
If myFoo.Bar.Items IsNot Nothing Then
...
코드는 테스트하고 Items
모두 동안 myFoo
과 Bar
도 아무것도 할 수있다. 해결책은 한번에 전체 쇄상 또는 물체 중 하나의 경로를 테스트 할 수있다 :
If (myFoo IsNot Nothing) AndAlso
(myFoo.Bar IsNot Nothing) AndAlso
(myFoo.Bar.Items IsNot Nothing) Then
....
AndAlso
중요하다. 첫 번째 False
조건에 도달 하면 후속 테스트는 수행되지 않습니다 . 이를 통해 코드는 한 번에 하나의 '레벨'로 객체를 안전하게 '드릴' 할 수 있으며 유효한 것으로 판단 된 myFoo.Bar
경우에만 평가할 myFoo
수 있습니다. 복잡한 객체를 코딩 할 때 객체 체인 또는 경로가 상당히 길어질 수 있습니다.
myBase.myNodes(3).Layer.SubLayer.Foo.Files.Add("somefilename")
null
객체 의 '다운 스트림'을 참조하는 것은 불가능 합니다. 이것은 컨트롤에도 적용됩니다.
myWebBrowser.Document.GetElementById("formfld1").InnerText = "some value"
여기에 myWebBrowser
또는 Document
아무것도 없거나 formfld1
요소가 없을 수 있습니다.
Dim cmd5 As New SqlCommand("select Cartons, Pieces, Foobar " _
& "FROM Invoice where invoice_no = '" & _
Me.ComboBox5.SelectedItem.ToString.Trim & "' And category = '" & _
Me.ListBox1.SelectedItem.ToString.Trim & "' And item_name = '" & _
Me.ComboBox2.SelectedValue.ToString.Trim & "' And expiry_date = '" & _
Me.expiry.Text & "'", con)
무엇보다도이 코드는 사용자가 하나 이상의 UI 컨트롤에서 무언가를 선택하지 않았을 것으로 예상하지 않습니다. ListBox1.SelectedItem
잘 될 수 Nothing
있으므로 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
. 결과적으로 :
somevar
아무것도가 없기 때문에 할당은 즉시 NRE가 발생합니다 .Text
속성을나중에 배열 요소를 참조하면 NRE가 발생합니다. Form_Load
이상한 버그로 인해이 작업을 수행 하면 IDE 에서 예외가 발생했을 때보고 하지 않을 수 있습니다 . 나중에 코드에서 배열을 사용하려고하면 예외가 나타납니다 . 이 "자동 예외"는 이 게시물에서 자세히 설명 합니다. 우리의 목적을 위해, 핵심은 폼 ( Sub New
또는 Form Load
이벤트) 을 생성하는 동안 치명적인 문제가 발생 하면 예외가보고되지 않고 코드가 프로 시저를 종료하고 폼만 표시한다는 것입니다.
NRE 이후에는 귀하 Sub New
또는 Form Load
이벤트의 다른 코드 가 실행 되지 않으므로 다른 많은 것들이 초기화되지 않은 채 남아 있을 수 있습니다.
Sub Form_Load(..._
'...
Dim name As String = NameBoxes(2).Text ' NRE
' ...
' More code (which will likely not be executed)
' ...
End Sub
참고 이 어떤 적용 및 모든 제어 및 구성 요소 참조 그들이 어디에 이러한 불법을 :
Public Class Form1
Private myFiles() As String = Me.OpenFileDialog1.FileName & ...
Private dbcon As String = OpenFileDialog1.FileName & ";Jet Oledb..."
Private studentName As String = TextBox13.Text
부분 치료
VB가 경고를 제공하지 않는 것이 궁금하지만 해결 방법은 컨테이너를 양식 레벨에서 선언 하는 것이지만 컨트롤 이 존재 하면 양식로드 이벤트 핸들러에서 컨테이너를 초기화 하는 것입니다 . 코드가 호출 후에 만 수행 할 수 있습니다 .Sub New
InitializeComponent
' Module level declaration
Private NameBoxes as TextBox()
Private studentName As String
' Form Load, Form Shown or Sub New:
'
' Using the OP's approach (illegal using OPTION STRICT)
NameBoxes = New TextBox() {Me.Controls("TextBox1"), Me.Controls("TestBox2"), ...)
studentName = TextBox32.Text ' For simple control references
배열 코드가 아직 숲에서 나오지 않았을 수 있습니다. 컨테이너 컨트롤 ( GroupBox
또는 같은)에있는 컨트롤 Panel
은 찾을 수 없습니다 Me.Controls
. 해당 패널 또는 GroupBox의 Controls 컬렉션에 있습니다. 컨트롤 이름의 철자가 틀리면 ( "TeStBox2"
) 컨트롤도 반환되지 않습니다 . 이러한 경우 Nothing
해당 배열 요소에 다시 저장되며 참조를 시도하면 NRE가 발생합니다.
당신이 찾고있는 것을 알았으므로 이제 쉽게 찾을 수 있어야합니다.
"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 Function
와 함께 Return Nothing
,하지만 문제가 해결되지 않습니다. someCondition = False
NRE가 발생할 때 리턴을 사용하려고하는 모든 것 :
bList = myFoo.BarList()
For Each b As Bar in bList ' EXCEPTION
...
치료제
Exit Function
함수에서로 교체하십시오 Return bList
. 비어있는 것을 반환하는 List
것은 반환하는 것과 다릅니다 Nothing
. 반환 된 객체가 될 수있는 경우 Nothing
, 사용하기 전에 테스트하십시오.
bList = myFoo.BarList()
If bList IsNot Nothing Then...
잘못 구현 된 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
이것은 예상대로 객체가 생성되지 않는 경우이지만 empty의 카운터 유용성을 보여줍니다 Catch
.
SQL에 여분의 쉼표가 있으며 ( 'mailaddress'뒤)에 예외가 발생 .ExecuteReader
합니다. (가) 후 Catch
아무것도하지 않는다, Finally
정리를 수행하려고하지만, 수 없습니다 이후 Close
널 DataReader
개체, 새로운 NullReferenceException
결과.
빈 Catch
블록은 악마의 놀이터입니다. 이 OP는 그가 Finally
블록 에서 NRE를 얻은 이유에 당황했습니다 . 다른 상황에서는 빈 공간으로 Catch
인해 더 많은 다운 스트림이 건초로 이동하여 잘못된 장소에서 문제를 찾는 데 시간을 소비하게됩니다. 위에서 설명한 "자동 예외"는 동일한 엔터테인먼트 가치를 제공합니다.
치료제
빈 Try / Catch 블록을 사용하지 마십시오. 코드 충돌을 일으켜 a) 원인을 식별합니다. b) 위치를 식별하고 c) 적절한 해결책을 적용하십시오. Try / Catch 블록은 예외를 해결할 자격이있는 사람 (개발자)의 예외를 숨기려는 것이 아닙니다.
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
경우 CheckBox
와 chkName
찾을 수 없습니다 (또는이 존재 GroupBox
), 다음 chk
아무것도 될 것 예외가 발생합니다 어떤 속성을 참조하려고 시도.
치료제
If (chk IsNot Nothing) AndAlso (chk.Checked) Then ...
DGV에는 다음과 같은 몇 가지 단점이 있습니다.
dgvBooks.DataSource = loan.Books
dgvBooks.Columns("ISBN").Visible = True ' NullReferenceException
dgvBooks.Columns("Title").DefaultCellStyle.Format = "C"
dgvBooks.Columns("Author").DefaultCellStyle.Format = "C"
dgvBooks.Columns("Price").DefaultCellStyle.Format = "C"
경우 dgvBooks
이있다 AutoGenerateColumns = True
, 그것은 열을 만들 것이다, 그러나이 이름을 참조 할 때 위의 코드가 실패 그래서, 그 이름을하지 않습니다.
치료제
열 이름을 수동으로 지정하거나 색인으로 참조하십시오.
dgvBooks.Columns(0).Visible = True
xlWorkSheet = xlWorkBook.Sheets("sheet1")
For i = 0 To myDGV.RowCount - 1
For j = 0 To myDGV.ColumnCount - 1
For k As Integer = 1 To myDGV.Columns.Count
xlWorkSheet.Cells(1, k) = myDGV.Columns(k - 1).HeaderText
xlWorkSheet.Cells(i + 2, j + 1) = myDGV(j, i).Value.ToString()
Next
Next
Next
당신이하는 경우 DataGridView
가 AllowUserToAddRows
로 True
(기본값) Cells
하단의 빈에서 / 새 행이 모두 포함됩니다 Nothing
. 내용 (예 :)을 사용하려고 ToString
하면 NRE가 발생합니다.
치료제
For/Each
루프를 사용 하여 IsNewRow
특성을 테스트하여 마지막 행인지 판별하십시오. 이것은 AllowUserToAddRows
사실이든 아니든 작동합니다 .
For Each r As DataGridViewRow in myDGV.Rows
If r.IsNewRow = False Then
' ok to use this row
For n
루프를 사용하는 경우 행 수를 수정하거나 true 일 Exit For
때 사용하십시오 IsNewRow
.
특정 상황에서 항목 사용하려고 My.Settings
a가되는 StringCollection
NullReference에 당신이 그것을 처음 사용할 때 발생할 수 있습니다. 해결책은 동일하지만 명확하지 않습니다. 치다:
My.Settings.FooBars.Add("ziggy") ' foobars is a string collection
VB가 설정을 관리하고 있으므로 컬렉션을 초기화 할 것으로 기대하는 것이 합리적입니다. 이전에 컬렉션에 초기 항목을 추가 한 경우에만 설정 편집기에서 수행됩니다. 항목이 추가 될 때 컬렉션이 (명확하게) 초기화되기 때문에 Nothing
설정 편집기에 추가 할 항목이 없을 때 컬렉션이 유지 됩니다.
치료제
Load
필요한 경우 양식의 이벤트 핸들러 에서 설정 콜렉션을 초기화하십시오 .
If My.Settings.FooBars Is Nothing Then
My.Settings.FooBars = New System.Collections.Specialized.StringCollection
End If
일반적으로 Settings
컬렉션은 응용 프로그램을 처음 실행할 때만 초기화하면됩니다. 다른 해결 방법은 프로젝트-> 설정 | FooBars , 프로젝트를 저장 한 다음 가짜 값을 제거하십시오.
아마도 New
운영자를 잊었을 것입니다 .
또는
초기화 된 객체를 코드에 반환하기 위해 완벽하게 수행한다고 가정하지는 않았습니다.
컴파일러 경고를 무시하지 말고 Option Strict On
항상 사용하십시오 .
또 다른 시나리오는 널 오브젝트를 값 유형 으로 캐스트 할 때 입니다. 예를 들어 아래 코드는 다음과 같습니다.
object o = null;
DateTime d = (DateTime)o;
NullReferenceException
캐스트를 던질 것 입니다. 위의 샘플에서는 매우 분명해 보이지만 소유하지 않은 일부 코드에서 null 객체가 반환되고 캐스트가 일부 자동 시스템에 의해 생성되는보다 "늦은 바인딩"복잡한 시나리오에서 발생할 수 있습니다.
이에 대한 한 가지 예는 Calendar 컨트롤이있는이 간단한 ASP.NET 바인딩 조각입니다.
<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />
여기에, SelectedDate
의 - 속성 사실상 DateTime
종류 -의 Calendar
웹 컨트롤 유형 및 완벽하게 뭔가 널 (null)을 반환 할 수 바인딩. 암시 적 ASP.NET 생성기는 위의 캐스트 코드와 동등한 코드를 만듭니다. 그리고 이것은 NullReferenceException
잘 컴파일되는 ASP.NET 생성 코드에 있기 때문에 발견하기가 매우 어렵습니다 ...
DateTime x = (DateTime) o as DateTime? ?? defaultValue;
그것은 문제의 변수가 아무것도 지적하지 않음을 의미합니다. 나는 이것을 이렇게 생성 할 수있다 :
SqlConnection connection = null;
connection.Open();
변수 " connection
"를 선언했지만 아무 것도 가리 키지 않기 때문에 오류가 발생 합니다. 회원에게 전화를 걸 때 "Open
" 이를 해결할 참조가 없으며 오류가 발생합니다.
이 오류를 피하려면
object == null
.JetBrains의 Resharper 도구는 코드에서 null 참조 오류가 발생할 가능성이있는 모든 위치를 식별하여 null 검사를 수행 할 수 있습니다. 이 오류는 버그의 가장 큰 원인 인 IMHO입니다.
이는 코드에서 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
}
이 예외가 발생하는 예는 다음과 같습니다. 무언가를 확인하려고하면 null입니다.
예를 들면 다음과 같습니다.
string testString = null; //Because it doesn't have a value (i.e. it's null; "Length" cannot do what it needs to do)
if (testString.Length == 0) // Throws a nullreferenceexception
{
//Do something
}
.NET 런타임은 인스턴스화되지 않은 무언가, 즉 위의 코드에서 작업을 수행하려고 할 때 NullReferenceException을 발생시킵니다.
메소드가 전달되는 것이 널 (null)이 아닌 것으로 예상하는 경우 일반적으로 방어 조치로 발생하는 ArgumentNullException과 비교합니다.
자세한 내용은 C # NullReferenceException 및 Null Parameter에 있습니다.
C # 8.0, 2019 업데이트 : Nullable 참조 유형
C # 8.0은 널 입력 가능 참조 유형 과 널 입력 불가능 참조 유형을 도입 합니다 . 따라서 NullReferenceException 을 피하려면 널 입력 가능 참조 유형 만 점검해야합니다. .
참조 유형을 초기화하지 않고 해당 속성 중 하나를 설정하거나 읽으려는 경우 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가 발생할 수 없습니다 . 참조 유형을 다룰 때주의를 기울여야 합니다 !
이름에서 알 수 있듯이 참조 유형 만 참조를 보유하거나 문자 그대로 아무 것도 가리킬 수 없습니다 (또는 '널'). 반면에 값 유형에는 항상 값이 포함됩니다.
참조 유형 (이 유형을 확인해야 함) :
값 유형 (단순히 무시할 수 있음) :
NullReferenceExceptions
발생할 수있는 또 다른 경우 는 as
연산자 의 (잘못된) 사용입니다 .
class Book {
public string Name { get; set; }
}
class Car { }
Car mycar = new Car();
Book mybook = mycar as Book; // Incompatible conversion --> mybook = null
Console.WriteLine(mybook.Name); // NullReferenceException
여기 Book
와 Car
호환되지 않는 유형이다; a Car
로 변환 / 캐스트 할 수 없습니다 Book
. 이 캐스트가 실패하면를 as
반환합니다 null
. mybook
이 후 사용 하면NullReferenceException
.
일반적 as
으로 다음과 같이 캐스트 또는을 사용해야 합니다.
타입 변환이 항상 성공할 것으로 기대한다면 (즉, 객체가 무엇보다 앞서야하는지 알고 있다면) 캐스트를 사용해야합니다.
ComicBook cb = (ComicBook)specificBook;
이 유형의 알 수없는, 그러나 당신이 원하는 경우에 시도 특정 유형으로 사용하기 위해, 다음 사용 as
:
ComicBook cb = specificBook as ComicBook;
if (cb != null) {
// ...
}
널값 참조가 포함 된 오브젝트를 사용하고 있습니다. 따라서 null 예외가 발생합니다. 이 예에서 문자열 값은 null이며 길이를 확인할 때 예외가 발생했습니다.
예:
string value = null;
if (value.Length == 0) // <-- Causes exception
{
Console.WriteLine(value); // <-- Never reached
}
예외 오류는 다음과 같습니다.
처리되지 않은 예외 :
System.NullReferenceException : 개체 참조가 개체의 인스턴스로 설정되지 않았습니다. Program.Main ()에서
하지만 무엇 원인 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인지 Null인지 확인해야 str2
합니다.
var x = str1.Trim() + str2.Trim();
일단 여기서 예외가 던져가있는 한, 그것은 널 값이 어디에 있는지 알아 이유 뒤쪽에 보통 사소한 [잘못] 소개 -
예외의 원인을 이해하는 데 필요한 시간을 가지십시오. 널 표현식을 검사하십시오. 이러한 널 표현식을 초래할 수있는 이전 표현식을 검사하십시오. 중단 점을 추가 하고 프로그램을 적절히 단계별로 진행하십시오. 디버거를 사용하십시오.
1 Break on Throws가 너무 공격적이며 .NET 또는 타사 라이브러리의 NPE에서 디버거가 중지 된 경우 User-Unhandled 에서 Break를 사용하여 포착 된 예외를 제한 할 수 있습니다. 또한 VS2012에는 Just My Code 가 도입 되어 활성화하는 것이 좋습니다.
Just My Code를 사용하여 디버깅하는 경우 동작이 약간 다릅니다. 내 코드 만 사용으로 설정하면 디버거는 내 코드 외부에서 발생하고 내 코드를 통과하지 못하는 CLR (first-chance common language runtime) 예외를 무시합니다.
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<>
인스턴스를 복싱 할 때 런타임에서 사용하는 특수 규칙으로 인해 발생 합니다.
엔티티 프레임 워크에서 사용되는 엔티티의 클래스 이름이 웹 양식 코드 숨김 파일의 클래스 이름과 동일한 경우를 추가하십시오.
코드 숨김 클래스가 Contact 인 웹 양식 Contact.aspx가 있고 엔터티 이름이 Contact이라고 가정합니다.
그런 다음 context를 호출하면 다음 코드에서 NullReferenceException이 발생합니다 .SaveChanges ()
Contact contact = new Contact { Name = "Abhinav"};
var context = new DataContext();
context.Contacts.Add(contact);
context.SaveChanges(); // NullReferenceException at this line
완전성을 위해 DataContext 클래스
public class DataContext : DbContext
{
public DbSet<Contact> Contacts {get; set;}
}
및 연락 엔티티 클래스. 때때로 엔티티 클래스는 부분 클래스이므로 다른 파일에서도 확장 할 수 있습니다.
public partial class Contact
{
public string Name {get; set;}
}
엔티티 및 코드 숨김 클래스가 모두 동일한 네임 스페이스에있는 경우 오류가 발생합니다. 이 문제를 해결하려면 Contact.aspx의 엔터티 클래스 또는 코드 숨김 클래스의 이름을 바꾸십시오.
이유 나는 여전히 그 이유에 대해 확신하지 못한다. 그러나 엔터티 클래스가 System.Web.UI.Page를 확장 할 때마다이 오류가 발생합니다.
논의를 위해 DbContext.saveChanges ()의 NullReferenceException을 살펴보십시오.
이 예외가 발생할 수있는 또 다른 일반적인 경우는 단위 테스트 중에 클래스를 조롱하는 것입니다. 사용되는 조롱 프레임 워크에 관계없이 모든 적절한 수준의 클래스 계층이 제대로 조롱되었는지 확인해야합니다. 특히, 모든 속성HttpContext
테스트중인 코드에서 참조하는 조롱해야합니다.
다소 자세한 예제는 " 사용자 정의 AuthorizationAttribute 테스트시 NullReferenceException 발생 "을 참조하십시오 .
나는 이것에 대답하는 데 다른 관점을 가지고 있습니다. 이런 종류의 대답은 "어떻게 피할 수 있습니까? "
MVC 애플리케이션과 같이 서로 다른 계층 에서 작업 할 때 컨트롤러는 비즈니스 운영을 호출하는 서비스가 필요합니다. 이러한 시나리오에서는 Dependency Injection Container 를 사용하여 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();
}
}
의 문제에 "나는 그것에 대해 무엇을해야" 많은 답변이있을 수 있습니다.
개발 중에 이러한 오류 조건 을 방지하는보다 "공식적인"방법은 코드에서 계약 에 따라 디자인을 적용 하는 것 입니다 . 즉 , 개발하는 동안 클래스 불변 값을 설정 하거나 시스템의 기능 / 메소드 전제 조건 및 사후 조건을 설정해야합니다.
요컨대, 클래스 불변 은 클래스에 정상적인 사용에서 위반되지 않는 제약이 있는지 확인합니다 (따라서 클래스가 일관성이없는 상태에 있지 않음 ). 전제 조건 은 함수 / 메소드에 대한 입력으로 제공된 데이터가 일부 제한 조건 세트를 따라야하며 이를 위반 하지 않아야 함을 의미하며 , 사후 조건 은 함수 / 메소드 출력이 설정된 제한 조건을 다시 위반하지 않고 다시 설정 제한 조건을 따라야 함을 의미합니다. 계약 조건은해야 결코 그러므로되는 동안, 디버그 모드에서 실제로 체크 계약에 의해 설계, 버그없는 프로그램을 실행하는 동안 위반되지 릴리스에서 비활성화 개발 된 시스템 성능을 최대화하기 위해.
이런 식으로 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 애플리케이션에 대한 Code Contracts 프로젝트가 존재합니다.
또는 어설 션을 사용하여 계약 별 디자인을 적용 할 수 있습니다 .
업데이트 : 이 용어는 에펠 프로그래밍 언어의 디자인과 관련하여 Bertrand Meyer 에 의해 만들어졌습니다 .
NullReferenceException
null 객체의 속성에 액세스하려고하거나 문자열 값이 비어 있고 문자열 메서드에 액세스하려고하면 A 가 발생합니다.
예를 들면 다음과 같습니다.
빈 문자열의 문자열 메소드에 액세스 한 경우 :
string str = string.Empty;
str.ToLower(); // throw null reference exception
null 객체의 속성에 액세스 한 경우 :
Public Class Person {
public string Name { get; set; }
}
Person objPerson;
objPerson.Name /// throw Null refernce Exception
String.Empty.ToLower()
null 참조 예외를 throw하지 않습니다. 빈 문자열 임에도 불구하고 실제 문자열을 나타냅니다 (예 :) ""
. 여기에는 호출 할 객체가 ToLower()
있으므로 null 참조 예외를 throw하는 것은 의미가 없습니다.
TL; DR :Html.Partial
대신에 사용해보십시오Renderpage
다음 Object reference not set to an instance of an object
과 같이 모델을 보내 뷰 내에서 뷰를 렌더링하려고 할 때 얻고 있습니다 .
@{
MyEntity M = new MyEntity();
}
@RenderPage("_MyOtherView.cshtml", M); // error in _MyOtherView, the Model was Null
디버깅 결과 모델이 MyOtherView 내부에 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가 앰퍼샌드와 괄호를 잘못 읽고 있기 때문에 느낌이 들었습니다.
Html.Partial
하지@Html.Partial
Null
그렇습니다), 모델을 전송하는 방법에 오류가 있음을 알았습니다.
그것에 대해 무엇을 할 수 있습니까?
여기에는 null 참조가 무엇인지 그리고 그것을 디버깅하는 방법을 설명하는 좋은 답변이 많이 있습니다. 그러나 문제를 방지하거나 최소한 쉽게 잡을 수있는 방법은 거의 없습니다.
인수 확인
예를 들어, 메소드는 다른 인수가 널인지 확인 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 Code Contracts"가 있습니다 : Introducing Code Contracts .
"PostSharp"도 있는데 다음과 같은 속성을 사용할 수 있습니다.
public void DoSometing([NotNull] obj)
그렇게하면 빌드 프로세스의 PostSharp 부분을 obj
런타임에 null로 검사합니다. 참조 : PostSharp 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
므로 필요한 곳 어디에서나 사용할 수 있습니다. 예를 들어 Person
객체를 다음과 같은 메소드로 전달할 수 있습니다 NotNull<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
전체 식인 경우를 반환합니다 null
.
이를 통해 일부 경우에 수행해야하는 널 검사 수가 줄어 듭니다. 구문은 각 점 앞에 물음표를 넣는 것입니다. 예를 들어 다음 코드를 사용하십시오.
var address = country?.State?.County?.City;
그것이 속성이라고 불리는 country
유형의 객체 라고 상상해보십시오 . 만약 , , , 또는 이다 다음 널 (null) 주소 null`.Country
State
country
State
County
City
null
address will be
. Therefore you only have to check whether
is
훌륭한 기능이지만 정보를 덜 제공합니다. 4 중 어느 것이 null인지는 분명하지 않습니다.
Nullable처럼 내장되어 있습니까?
C #은 축약 형입니다 . Nullable<T>
형식 뒤에 물음표를 붙여서 Null을 만들 수 있습니다 int?
.
C #에 NotNull<T>
위 의 구조체와 비슷한 것이 있고 느낌표 (!)와 비슷한 속기가 있으면 다음과 같이 쓸 수 public void WriteName(Person! person)
있습니다.
흥미롭게도,이 페이지의 어떤 답변도 두 가지 경우를 언급하지 않습니다.
.NET의 일반 사전은 스레드로부터 안전하지 않으며 두 개의 동시 스레드에서 키에 액세스하려고 할 때 때때로NullReference
(더 자주) a를 던질 수 있습니다 KeyNotFoundException
. 이 경우 예외는 오해의 소지가 있습니다.
코드에 NullReferenceException
의해 a 가 발생 unsafe
하면 포인터 변수를보고 그 변수를 확인하십시오 IntPtr.Zero
. 어느 것이 똑같지 만 ( "널 포인터 예외") 안전하지 않은 코드에서는 변수가 종종 값 유형 / 배열 등에 캐스트되고, 값 유형이 어떻게 이것을 던질 수 있을지 궁금해 벽에 머리를 부딪칩니다. 예외.
(필요하지 않은 한 안전하지 않은 코드를 사용하지 않는 또 다른 이유)
null
어떤 면에서 다른 가요?
c # 6의 Null 조건부 연산자를 사용하여 NullReferenceException을 깔끔하게 수정하고 적은 수의 코드를 작성하여 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의 값이 지정됩니다.
자세한 내용 : Null 조건부 연산자
오류 개체 "개체 참조가 개체의 인스턴스로 설정되지 않았습니다."는 인스턴스 개체를 개체 참조에 할당하지 않았지만 여전히 해당 개체의 속성 / 방법에 액세스하고 있음을 나타냅니다.
예를 들어, myClass라는 클래스가 있고 prop1 속성이 하나 있다고 가정 해 봅시다.
public Class myClass
{
public int prop1 {get;set;}
}
이제 다음과 같이 다른 클래스 에서이 prop1에 액세스하고 있습니다.
public class Demo
{
public void testMethod()
{
myClass ref = null;
ref.prop1 = 1; //This line throws error
}
}
위의 행은 myClass 클래스의 참조가 선언되었지만 인스턴스화되지 않았거나 객체의 인스턴스가 해당 클래스의 참조에 지정되지 않았기 때문에 오류를 발생시킵니다.
이 문제를 해결하려면 인스턴스화해야합니다 (객체를 해당 클래스의 참조로 지정).
public class Demo
{
public void testMethod()
{
myClass ref = null;
ref = new myClass();
ref.prop1 = 1;
}
}
사용하려는 클래스의 객체가 인스턴스화되지 않은 경우 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이 발생합니다.
간단히 말해서,
작성되지 않았거나 현재 메모리에없는 오브젝트에 액세스하려고합니다.
그래서 이것을 해결하는 방법 :
디버그하고 디버거를 중단시킵니다 ... 직접 깨진 변수로 이동합니다 ... 이제 작업을 간단히 수정 하는 것입니다. 적절한 위치에서 새 키워드를 사용하십시오 .
오브젝트가 없기 때문에 일부 데이터베이스 명령 에서 발생한 경우 널 점검을 수행하고 처리하기 만하면됩니다.
if (i == null) {
// Handle this
}
가장 어려운 것은 .. GC가 이미 개체를 수집 한 경우 ... 이것은 일반적으로 문자열을 사용하여 개체를 찾으려고 할 때 발생합니다. 즉, 개체 이름으로 개체를 찾은 경우 GC가 이미 발생할 수 있습니다. 정리하기 ... 찾기가 어렵고 상당히 문제가 될 것입니다 ... 이것을 해결하는 더 좋은 방법은 개발 과정에서 필요한 곳 어디에서나 널 검사를하는 것입니다. 이렇게하면 많은 시간이 절약됩니다.
이름으로 찾음에 따라 일부 프레임 워크에서 문자열을 사용하여 FIndObject를 찾을 수 있으며 코드는 다음과 같습니다. FindObject ( "ObjectName");
말 그대로 NullReferenceExeption을 수정하는 가장 쉬운 방법은 두 가지 방법이 있습니다. 예를 들어 스크립트가 첨부 된 게임 오브젝트와 rb (rigidbody)라는 변수가있는 경우 게임을 시작할 때이 변수는 null로 시작합니다.
컴퓨터에 해당 변수에 저장된 데이터가 없기 때문에 NullReferenceExeption을 얻는 이유입니다.
예를 들어 RigidBody 변수를 사용하겠습니다.
실제로 몇 가지 방법으로 데이터를 실제로 쉽게 추가 할 수 있습니다.
rb = GetComponent<Rigidbody>();
Start()
또는 Awake()
함수에서 가장 잘 작동 합니다. rb = AddComponent<RigidBody>();
추가 참고 사항 : 개체에 구성 요소를 추가하고 단일 구성 요소를 추가 [RequireComponent(typeof(RigidBody))]
하지 않은 경우 클래스 선언 이상 (모든 사용 아래의 공간)을 입력 할 수 있습니다 .
즐기고 재미있는 게임 만들기!
이 예외가 발생할 수있는 일반적인 시나리오를 고려하면 맨 위에 객체가있는 속성에 액세스합니다.
전의:
string postalcode=Customer.Address.PostalCode;
//if customer or address is null , this will through exeption
여기에서 address가 null이면 NullReferenceException이 발생합니다.
따라서 실제로는 이러한 객체의 속성에 액세스하기 전에 항상 null 검사를 사용해야합니다 (특히 일반)
string postalcode=Customer?.Address?.PostalCode;
//if customer or address is null , this will return null, without through a exception
이것은 기본 적으로 Null 참조 예외 입니다. Microsoft는 다음과 같이 말합니다.
값이 null 인 유형의 멤버에 액세스하려고하면 NullReferenceException 예외가 발생합니다.
즉, 가치가없는 회원이 있고 해당 회원이 특정 작업을 수행하도록하는 경우 시스템은 의심의 여지없이 메시지를 던져
"잠깐만 요, 그 멤버는 가치가 없어서 당신이 맡고있는 작업을 수행 할 수 없습니다."
예외 자체는 무언가가 참조되고 있지만 값이 설정되지 않았다고 말합니다. 따라서 이는 값 유형이 널 입력 불가능하므로 참조 유형을 사용하는 동안에 만 발생 함을 나타냅니다.
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 값을 반환하거나 설정할 수있는 메서드, 속성, 컬렉션 등을 사용하는 것도이 예외의 원인 일 수 있습니다.
이 예외를 피할 수있는 다양한 방법과 방법이 있습니다.
명시 적 검사 : 개체, 속성, 메서드, 배열 및 컬렉션이 null인지 여부를 확인하는 전통을 준수해야합니다. if-else if-else 등과 같은 조건문을 사용하여 간단하게 구현할 수 있습니다.
예외 처리 :이 예외를 관리하는 중요한 방법 중 하나입니다. 간단한 try-catch-finally 블록을 사용하여이 예외를 제어하고 로그를 유지할 수도 있습니다. 응용 프로그램이 프로덕션 단계에있을 때 매우 유용합니다.
Null 연산자 : Null Coalescing 연산자 및 Null 조건부 연산자를 사용하여 값을 개체, 변수, 속성 및 필드로 설정할 수 있습니다.
디버거 : 개발자에게는 큰 디버깅 무기가 있습니다. 개발 단계에서 NullReferenceException에 직면 한 경우 디버거를 사용하여 예외 소스에 도달 할 수 있습니다.
내장 메소드 : GetValueOrDefault (), IsNullOrWhiteSpace () 및 IsNullorEmpty ()와 같은 시스템 메소드는 널을 점검하고 널값이있는 경우 기본값을 지정합니다.
이미 많은 좋은 답변이 있습니다. 내 블로그의 예제를 통해 자세한 설명을 확인할 수도 있습니다 .
이것이 도움이되기를 바랍니다!
빌드를 저장하거나 컴파일하는 동안이 메시지가 표시되면 모든 파일을 닫은 다음 파일을 열어 컴파일하고 저장하십시오.
나에게 그 이유는 파일 이름을 바꾸고 이전 파일이 여전히 열려 있기 때문입니다.