codememo

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

tipmemo 2023. 4. 18. 22:48
반응형

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

가 몇 개 되면 '코드가 요'NullReferenceException다음과 같이 말합니다.

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

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

원인이 무엇입니까?

결산

당신이 사용하려고 하는 것은null (오류)Nothing.NET (VB)NET)를 사용하다, '아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아,null는,, 아아도도 설설다다다않

것과 로, 른른 like like like like like like like like like like like like like like likenull 그렇다면null 방법 "A"에서는 방법 "B"가 a를 통과한 것일 수 있습니다.null 메서드 "A"로 이동합니다.

null츠키다

  1. 초기화되지 않은 개체 변수는 아무것도 가리키지 않습니다.이 경우 이러한 개체의 멤버에 액세스하면NullReferenceException.
  2. 개발자는 의미 있는 값이 없음을 나타내기 위해 의도적으로 사용하고 있습니다.C#에는 변수에 대한 늘 가능한 데이터 타입의 개념이 있습니다(데이터베이스 테이블에는 늘 가능한 필드가 있을 수 있습니다).할당할 수 있습니다.null예 를들 、 들 to 、 to to to to to to to to to to to to to to to ) 。int? a = null;입니다.Nullable<int> a = null;되어 을 나타냅니다 물음표는 격납이 허가되어 있음을 나타냅니다.nulla. 그 중 하실 수 있습니다.if (a.HasValue) {...} ★★★★★★★★★★★★★★★★★★★★★★.if (a==null) {...}. : 효효 、 를 . ) a예에서는 을 수 .a.Value으로, 「」를 통해서, 「」를 참조해 주세요.a
    를 통해 액세스 하는 것에 주의해 주세요.a.ValueInvalidOperationExceptionNullReferenceExceptionanull - 다른 - 미리 - - - 、 른 - 、 른 - 、 른 - 、 른 - 、 。int b; 같은 거 해야 요.if (a.HasValue) { b = a.Value; } 단축된 "" " " " " " " "if (a != null) { b = a; }.

부분에서는 하고 많은 이 자주 , 이mersmersmers the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the로 이어질 수 있다. 을 사용하다NullReferenceException.

자세한 것은 이쪽

runtimeNullReferenceException 는 항상 같은 것을 의미합니다.참조를 사용하려고 하면 참조가 초기화되지 않습니다(또는 일단 초기화되었지만 더 이상 초기화되지 않습니다.

, 는 ,, 조, this 。null 멤버(메서드 등에 할 수 .null 경우:'이것'은 다음과 같습니다.

string foo = null;
foo.ToUpper();

이렇게 하면NullReferenceException수 에 두 줄에 .ToUpper() stringnull.

디버깅

의스 of of of of of of of of of of of of of of of 의 찾을 수 ?NullReferenceExceptionVisual Studio의 디버깅에 관한 일반적인 규칙은 예외 자체를 확인하는 것 외에, 이름 위에 마우스를 올려놓고 변수를 검사하는 것 중 하나를 수행합니다(빠른 실행).Watch 창을 보거나 Locals 및 Autos와 같은 다양한 디버깅 패널을 사용합니다.

참조 위치를 확인하려면 참조 이름을 마우스 오른쪽 버튼으로 클릭하고 "Find All References(모든 참조 검색)"를 선택합니다.그런 다음 발견된 모든 위치에 중단점을 배치하고 디버거가 연결된 상태에서 프로그램을 실행할 수 있습니다.이러한 중단점에서 디버거가 중단될 때마다 참조가 null이 아니어야 하는지 여부를 판단하고 변수를 검사하고 참조가 예상되는 인스턴스를 가리키는지 확인해야 합니다.

이 방법으로 프로그램 흐름을 따라가면 인스턴스가 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늘 또는 ""로 할 수 .Identity무효로 하다

간접적인

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

하위(사용자) 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 이벤트 를 할 NothingVB.NET).

잘못된 명명 규칙:

필드의 이름을 로컬과 다르게 지정한 경우 필드를 초기화하지 않은 것을 알 수 있습니다.

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 빈 뷰 모델

의 할 때 @Model an ASP.NET MVC ViewModel요, 행동방법이 정해지면요.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 컨트롤 작성 순서 및 이벤트

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

의 변경XAML)label1 전에comboBox1철학을 (디자인 철학을 무시한 채는될 것입니다.NullReferenceException

★★★★★★★★★★를 실시합니다.as

var myThing = someObject as Thing;

건건 an an an an an an an가 .InvalidCastException 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아.null실패했을 때및 '실패했을 때'('했을 때('실패했을 때')someObject그 자체가 늘입니다).츠키노

FirstOrDefault() ★★★★★★★★★★★★★★★★★」SingleOrDefault()

버전 ' ' '」First() ★★★★★★★★★★★★★★★★★」Single()버전은 OrDefault를 반환합니다.null런런경경경경경경츠키노

앞지르다

foreach할 때 던지기null수집.보통 예기치 않은 원인으로 발생합니다.null컬렉션을 반환하는 메서드에서 발생합니다.

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

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

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

회피 방법

하세요.nullnull★★★★★★ 。

, 「 」가 될 경우는, 「 」가 됩니다.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

연산자 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):

이것은 때때로 안전 항법 또는 엘비스(모양에서 따온) 오퍼레이터라고도 불립니다.연산자 왼쪽에 있는 식이 null이면 오른쪽이 평가되지 않고 대신 null이 반환됩니다.즉, 다음과 같은 경우가 있습니다.

var title = person.Title.ToUpper();

, 이 예외가 는 이 조작이 콜을 때문입니다.ToUpper무효로 하다

»C# 5아래는 다음과 같이 보호할 수 있습니다.

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

이제 제목 변수는 예외를 발생시키는 대신 null이 됩니다.C# 6 에서는, 이것에 관한 보다 짧은 구문이 도입되고 있습니다.

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

가 '아까보다'가 .null 의 콜, 「」ToUpper만약의 경우 만들어지지 않는다.person.Titlenull.

물론, 당신은 여전히 확인해야 합니다.title★★★★★★에nullnull 연산자를 함께 합니다(null condition 'null condition' 'null condition' 'null condition' 'null condition' 'null condition' 'null condition' 'null condition').??디폴트값을 지정하려면 , 다음의 순서에 따릅니다.

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

하다 ifmyIntArraynull이은 , 을 반환합니다.null안전하게 확인하실 수 있습니다.elem = myIntArray[i];ith 요소를 반환합니다.

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

개개에 C# 8및은 변수에 대한 하고 값이 과 같은 null 는는로로 to to to to to or or or로 설정되어 있습니다.null하면, 타입을 으로 null로 할 수null.

및 는 null을 null 주석 컨텍스트 및 null 경고 컨텍스트를 할 수 .Nullablecsproj파일. 이 요소는 컴파일러가 유형의 nullability를 해석하는 방법과 생성되는 경고를 구성합니다.유효한 설정은 다음과 같습니다.

  • enable: 늘(null) 경고 nullable 경고 입니다.예를 들어 참조 유형(예: 문자열)의 변수는 Null이 아닙니다.무효
  • disable: null 가능한 주석 컨텍스트가 비활성화되어 있습니다.disabled.null 입니다.null 경고 컨텍스트는 되어 있습니다.참조 타입의 변수는 이전 버전의 C#과 마찬가지로 인식되지 않습니다.무효
  • safeonly: 늘(null)null safe only입니다.무효로 하다모든 안전상의 무효 경고가 유효하게 되어 있습니다.
  • warnings: null 가능한 주석 컨텍스트가 비활성화되어 있습니다. 경고 nullable 경고 입니다.이치노무효
  • safeonlywarnings: null 가능한 주석 컨텍스트가 비활성화되어 있습니다.null safe only입니다.이치노모든 안전상의 무효 경고가 유효하게 되어 있습니다.

늘값 한 구문을 됩니다.null " " " " " " " " null " " " " null " " " " " " " " " null " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "?변수 유형에 추가됩니다.

반복기에서 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) { ... }

ifwhatever이 되다nullMakeFrob 것이하실 수 .그러면 이렇게 하는 것이 옳다고 생각할 수 있습니다.

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

반복 로직을 방식과 방식을 사용하여 방식을 .null체크 후 반복기를 반환합니다., 이제 제, 제GetFrobs 해서 '이렇게 하다'라고 합니다null, 그 후 " " " " " " 가 실행됩니다.GetFrobsForReal는 시퀀스가 반복될 때 실행됩니다.

「 」의 하면,LINQ오브젝트에는 이 기법이 전체적으로 사용되고 있음을 알 수 있습니다.쓰기가 좀 더 투박하지만 늘 오류 디버깅이 훨씬 쉬워집니다.작성자의 편의를 위해서가 아니라 발신자의 편의를 위해서 코드를 최적화합니다.

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

C#에는, 이름에서 나타내듯이, 메모리 안전과 타입의 안전성을 제공하는 통상적인 안전 메커니즘이 적용되지 않기 때문에, 지극히 위험한 「스펙트」모드가 있습니다.메모리의 구조에 대해 철저하고 깊이 이해하지 않는 한 안전하지 않은 코드를 작성해서는 안 됩니다.

안전하지 않은 모드에서는 다음 두 가지 중요한 사항에 유의해야 합니다.

  • null 포인터를 참조 해제하면 null 참조를 참조 해제하는 것과 동일한 예외가 발생합니다.
  • 유효하지 않은 비대칭 포인터를 참조하면 상황에 따라서는 그 예외가 발생할 수 있습니다.

하려면 , 하면 좋은지 이 됩니다.은 NET을 생성합니다.NullReferenceException(이러한 에 해당됩니다.)Windows 의 「NET」 다른 운영체제에서도 같은 메커니즘이 사용됩니다.)

.Windows; 각 프로세스에는 운영체제에 의해 추적되는 메모리의 많은 "페이지"의 가상 메모리 공간이 할당됩니다.메모리의 각 페이지에는, 사용 방법을 결정하는 플래그가 설정되어 있습니다(읽기, 쓰기, 실행 등).맨 아래 페이지는 "어떤 방식으로든 사용될 경우 오류를 생성합니다"로 표시됩니다.

의 늘 와 늘 참조 C#는 내부적으로 숫자 0으로 나타나기 때문에 대응하는 메모리 스토리지로 참조 해제하려고 하면 운영체제에서 오류가 발생합니다. 후 .이 되어 「」로됩니다.NET은, NET 의 경우NullReferenceException.

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

두 번째 포인트는요?가상 메모리의 가장 낮은 페이지에 있는 비활성 포인터를 참조하면 동일한 운영 체제 오류가 발생하여 동일한 예외가 발생합니다.

왜게이 이? ???예를 들어, 2개의 int와 null과 같은 관리되지 않는 포인터를 포함하는 구조가 있다고 가정합니다.두 "int"는 ""를 참조합니다.CLR는 로케이션0 의 스토리지에 액세스 하지 않고, 로케이션4 의 스토리지에 액세스 합니다.단, 논리적으로는 null을 통해 해당 주소에 도달하기 때문에 이것은 null 참조 해제입니다.

하지 않은 때, 「」라고 메세지가 표시되는 는,NullReferenceException다만, 문제의 포인터는 늘일 필요는 없다는 점에 주의해 주세요.가장 아래 페이지의 모든 위치를 지정할 수 있으며, 이 예외가 발생합니다.

NullReference 예외: Visual Basic

NullReference ExceptionVisual Basic은 C#의 것과 다르지 않습니다.결국 둘 다 에서 정의된 동일한 예외를 보고하고 있습니다.둘 다 사용하는 NET Framework.Visual Basic 고유의 원인은 거의 없습니다(아마도 1개뿐입니다).

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

주의:

  1. 이치노프로젝트에 붙여넣을 코드는 없습니다.은 무엇이 입니다.NullReferenceException 및 (NRE), " " " " , " " " " " 。NRE는 여러 가지 방법으로 발생할 수 있기 때문에 이것이 유일한 원인이 될 가능성은 거의 없습니다.
  2. (Stack Overflow 투고로부터의) 예에서는 처음부터 최적의 방법을 나타내는 것은 아닙니다.
  3. 일반적으로 가장 간단한 치료법이 사용됩니다.

기본적인 의미

"Object not set to a instance of Object" 메시지는 초기화되지 않은 개체를 사용하려고 함을 의미합니다.이는 다음 중 하나로 요약됩니다.

  • 코드가 개체 변수를 선언했지만 초기화하지 않았습니다(인스턴스 생성 또는 '인스턴스').
  • 코드가 개체를 초기화할 것으로 가정했지만, 그렇지 않았습니다.
  • 다른 코드가 아직 사용 중인 개체를 조기에 비활성화했을 수 있습니다.

원인 찾기

Nothing 어떤 인지 살펴보는 그런 다음 초기화되지 않은 이유를 확인합니다. 위에 Visual Studio합니다. 은 Visual Studio(VS)가 됩니다.원인은Nothing.

IDE debug display

관련 코드에서 Try/Catch 블록, 특히 Catch 블록에 아무것도 없는 블록도 삭제해야 합니다.하려고 할 때 .Nothing이것은 문제의 정확한 위치를 파악하고 문제의 원인이 되는 개체를 식별할 수 있기 때문에 필요한 것입니다.

A MsgBox[ Catch ]에 표시됩니다.Error while...별 도움이 안 될 거야이 메서드에서는 실제 예외, 관련된 오브젝트, 심지어 발생한 코드 행까지 설명할 수 없기 때문에 스택 오버플로우 질문이 매우 불량하게 됩니다.

이 경우에도 하실 수 있습니다.Locals Window(디버깅 -> Windows -> 로컬)을 사용하여 오브젝트를 조사합니다.

문제가 무엇이고 어디에 있는지를 알게 되면 보통 새로운 질문을 게시하는 것보다 훨씬 쉽고 빠르게 해결할 수 있습니다.

다음 항목도 참조하십시오.

예와 구제책

클래스 오브젝트/인스턴스 생성

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

는 제는 the the the the the the the the theDimCashRegister 개체를 생성하지 않고 이름 있는 변수만 선언합니다.reg그 타입의 것.오브젝트 변수 선언과 인스턴스 작성은 별개의 문제입니다.

구제책

New할 수 .

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

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

나중에 인스턴스를 생성하는 것이 적절한 경우:

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

주의: 사용하지 마십시오.Dim한 번 즉, 컨스트럭터 포함)Sub New

Private reg As CashRegister
'...

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

그러면 로컬 변수가 생성됩니다.reg이 컨텍스트(서브)에만 존재합니다.reg이 ""인 " 변수Scope 에서 사용할 수 .Nothing.

작업자를 놓치는 것은 스택 오버플로우 질문에서 확인되는 첫 번째 원인입니다.

Visual Basic은 연산자를 사용하여 프로세스를 반복적으로 명확하게 하려고 합니다.오퍼레이터를 사용하면 새로운 오브젝트가 생성되고 오브젝트가 다른 초기화를 수행할 수 있는 컨스트럭터가 호출됩니다.

말하면, 「 」입니다.Dim (오류)Private)는 변수 및 변수만 선언합니다.Type변수의 범위는 모듈/클래스 전체에 존재하는지 프로시저에 로컬인지에 관계없이 선언된 위치에 따라 결정됩니다. 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

NRE가 ''는 'NRE'이기 때문입니다.barList선언된 것일 뿐 인스턴스화되지는 않습니다." " Foo또한 내부 인스턴스는 생성되지 않습니다.barList컨스트럭터에서 이 작업을 수행하려는 의도였을 수 있습니다.

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

이전과 같이 이는 올바르지 않습니다.

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

자세한 내용은 클래스를 참조하십시오.


데이터 공급자 개체

많은 오브젝트가 존재할 수 있기 때문에 데이터베이스 조작은 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데이터 집합 개체가 선언되었지만 인스턴스가 생성되지 않았습니다.DataAdapter기존 데이터를 채울 수 있습니다.DataSet작성하지 않습니다.이 경우,ds는 로컬 변수입니다.IDE는 다음과 같이 경고합니다.

img

모듈/클래스 레벨 변수로 선언된 경우(의 경우와 같음)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.없었다DataTable"Employee"라는 이름이 생성되었기 때문에NullReferenceException접속을 시도하고 있습니다.또 다른 잠재적인 문제는 다음과 같은 일이 일어날 것이라고 가정하는 것이다.ItemsSQL에 WHERE 절이 포함되어 있는 경우에는 그렇지 않을 수 있습니다.

구제책

이것은 1개의 테이블을 사용하기 때문에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")존재하지 않는 테이블을 참조합니다.

Remedy는 동일합니다.테이블을 인덱스로 참조해 주세요.

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

DataTable Class도 참조하십시오.


개체 경로/네스트됨

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요소가 존재하지 않을 수 있습니다.


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.SelectedItem그럴지도 모른다Nothing,그렇게ListBox1.SelectedItem.ToStringNRE가 됩니다.

구제책

데이터 사용 전 검증(사용도 가능)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그 결과:

  • 목록과 컬렉션은 비어 있습니다.
  • 어레이에는 아무것도 포함되지 않는 5가지 요소가 포함됩니다.
  • somevar할당에 의해 즉시 NRE가 발생합니다.왜냐하면, NRE가 없는 것은 아무것도 없기 때문입니다..Text소유물

나중에 어레이 요소를 참조하면 NRE가 발생합니다.에서 이렇게 하면Form_Load이상한 버그로 인해 IDE가 예외를 보고하지 않을 수 있습니다.나중에 코드가 어레이를 사용하려고 하면 예외가 팝업 표시됩니다.이 「사일런트 예외」에 대해서는, 투고에서 자세하게 설명합니다.이 목적을 위해 중요한 것은 폼 작성 중에 중대한 일이 발생했을 때(Sub New또는Form Loadevent) 예외가 보고되지 않고 코드가 절차를 종료하고 양식만 표시할 수 있습니다.

다른 코드가 없기 때문에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가 경고를 제공하지 않는 것이 이상하지만 이 문제를 해결하려면 컨테이너를 폼레벨로 선언하지만 컨트롤이 존재할 경우 폼로드 이벤트핸들러로 초기화합니다.이것은 다음에서 실행할 수 있습니다.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가 발생합니다.

원하는 것을 알았기 때문에 쉽게 찾을 수 있을 것입니다.VS shows you the error of your ways

"Button 2"는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가 '모든 경로가 값을 반환하지 않으며 결과가 발생할 수 있음'을 경고하는 경우입니다.이 경고를 억제하려면 , 를 치환합니다.Exit Function와 함께Return Nothing그러나 그것은 문제를 해결하지 못한다.수익률을 사용하려고 하는 경우someCondition = FalseNRE가 됩니다.

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

이는 오브젝트가 예상대로 생성되지 않는 경우이지만 빈 카운터의 유용성도 보여줍니다.Catch.

SQL에는 ('mailaddress' 뒤에) 다음과 같은 예외가 발생하는 추가 쉼표가 있습니다..ExecuteReader.이후Catch아무것도 하지 않는다.Finally청소를 실행하려고 하지만 할 수 없기 때문에Close무효DataReader오브젝트, 완전히 새로운NullReferenceException결과.

비어 있다Catch블록은 악마의 놀이터입니다.이 OP는 그가 왜 NRE를 받았는지 이해할 수 없었다.Finally블록. 다른 상황에서는, 빈칸이Catch하류에서 훨씬 더 멀리 떨어진 곳에서 문제가 발생할 수 있으며, 이로 인해 문제를 해결하기 위해 잘못된 곳을 찾는 데 시간을 소비하게 될 수 있습니다.(위에서 설명한 '사일런트 예외'도 동일한 엔터테인먼트 가치를 제공합니다).

구제책

빈 Try/Catch 블록을 사용하지 마십시오.a) 원인을 파악하고 c) 적절한 해결책을 적용할 수 있도록 코드가 크래시되도록 합니다.Try/Catch 블록은 블록을 수정할 자격이 있는 사용자(개발자)에게 예외를 숨기려는 것이 아닙니다.


DBNull이 아무것도 아님

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

IsDBNull함수는 이 동일한지 여부를 테스트하기 위해 사용됩니다.System.DBNull: MSDN에서:

시스템DBNull 값은 개체가 누락되거나 존재하지 않는 데이터를 나타냄을 나타냅니다.DBNull은 변수가 아직 초기화되지 않았음을 나타내는 없음과 다릅니다.

구제책

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참조 타입의 경우 및 neverDBNull:

If getFoo IsNot Nothing Then...

컨트롤

Dim chk As CheckBox

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

만약 a가CheckBox와 함께chkName찾을 수 없다(또는 에 존재한다)GroupBox) 。chk[Nothing] 이 되어 속성을 참조하려고 하면 예외가 발생합니다.

구제책

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

Data Grid View

DGV에는 정기적으로 나타나는 몇 가지 이상한 점이 있습니다.

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

한다면dgvBooks가지다AutoGenerateColumns = True컬럼은 생성되지만 컬럼의 이름은 지정하지 않기 때문에 위의 코드는 컬럼을 이름으로 참조할 때 실패합니다.

구제책

열의 이름을 수동으로 지정하거나 인덱스로 참조합니다.

dgvBooks.Columns(0).Visible = True

예 2 - NewRow 주의

xlWorkSheet = xlWorkBook.Sheets("sheet1")

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

이 경우DataGridView가지다AllowUserToAddRows~하듯이True(디폴트),Cells아래 빈 줄/새 줄에 모두 포함됨Nothing. 대부분의 경우 콘텐츠 사용을 시도합니다(예:ToString)는 NRE가 됩니다.

구제책

를 사용하다For/Each루프를 사용하여 테스트하다IsNewRow마지막 행인지 아닌지를 판별하는 속성입니다.이 동작은AllowUserToAddRows가 참인지 아닌지는,

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

를 사용하는 경우For n루프, 행 수 변경 또는 사용Exit For언제IsNewRow정말이에요.


My.Settings(String Collection)

특정 상황에서는 다음 항목을 사용하려고 합니다.My.Settings즉,StringCollection를 처음 사용할 때 NullReference가 발생할 수 있습니다.해결책은 동일하지만 명확하지는 않습니다.고려사항:

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

VB가 설정을 관리하고 있으므로 수집을 초기화할 것으로 예상하는 것이 합리적입니다.하지만 이전에 (설정 편집기에서) 컬렉션에 초기 엔트리를 추가한 경우에만 해당됩니다.항목이 추가될 때 컬렉션이 초기화되기 때문에(분명히) 남아 있습니다.Nothing추가할 항목이 설정 편집기에 없는 경우.

구제책

폼의 설정 컬렉션을 초기화합니다.Load이벤트 핸들러(필요한 경우/필요한 경우):

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

일반적으로는Settings수집은 응용 프로그램을 처음 실행할 때만 초기화하면 됩니다.대체 대책으로는 [Project]-> [ Settings ]| [ Foo Bars ]컬렉션에 초기값을 추가하고 프로젝트를 저장한 후 가짜값을 삭제하는 방법이 있습니다.


요점

아마 잊으셨을 거예요New교환입니다.

또는

초기화된 개체를 코드로 되돌리기 위해 완벽하게 수행한다고 가정한 작업이 수행되지 않았습니다.

컴파일러 경고를 무시하지 않고 사용Option Strict On(항상).


MSDN NullReference 예외

또 다른 시나리오는 null 개체를 값 유형에 캐스팅하는 것입니다.예를 들어, 다음 코드는 다음과 같습니다.

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

그것은 을 던질 것이다.NullReferenceException출연진에게.위의 샘플에서는 매우 명백해 보이지만, 이것은 사용자가 소유하지 않은 코드에서 null 객체가 반환되고, 예를 들어 캐스트가 자동 시스템에 의해 생성되는 보다 "늦은 바인딩"의 복잡한 시나리오에서 발생할 수 있습니다.

예를 들어 이 단순한 ASP가 있습니다.달력 컨트롤이 있는 NET 바인딩 조각:

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

여기서,SelectedDate사실은 재산이다 - 의DateTime의 유형 -CalendarWeb Control 타입과 바인딩은 완전히 null을 반환할 수 있습니다.암묵적인 ASPNET Generator는 위의 캐스트 코드와 동일한 코드를 만듭니다.그리고 이게 더 큰 문제가 될 거야NullReferenceExceptionASP에 있기 때문에 발견하기가 매우 어렵습니다.NET이 생성한 코드는 미세 컴파일...

이는 코드가 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
}

즉, 문제의 변수가 아무것도 가리키지 않는다는 것입니다.다음과 같이 생성할 수 있습니다.

SqlConnection connection = null;
connection.Open();

이 경우 오류가 발생합니다. 변수를 선언한 동안 "connection"아무것도 가리키지 않습니다.멤버에게 전화를 걸려고 하면Open해결할 참조가 없으며 오류가 발생합니다.

이 오류를 방지하려면:

  1. 개체를 사용하여 작업을 수행하기 전에 항상 개체를 초기화하십시오.
  2. 개체가 null인지 확실하지 않은 경우 에서 확인하십시오.object == null.

JetBrains의 ReSharper 도구는 코드 내에서 null 참조 오류가 발생할 가능성이 있는 모든 위치를 식별하여 null 체크를 수행할 수 있도록 합니다.이 에러는 버그 발생원인 IMHO의 1위입니다.

시나리오에 관계없이 원인은 에서 항상 동일하다는 점에 주의해 주십시오.네트워크:

값이 다음과 같은 기준 변수를 사용하려고 합니다.Nothing/null값이 다음과 같은 경우Nothing/null즉, 참조 변수가 힙에 존재하는 객체의 인스턴스에 대한 참조를 실제로 보유하고 있지 않음을 의미합니다.

변수에 어떤 것을 할당하지 않았거나 변수에 할당된 값의 인스턴스를 생성하지 않았거나 변수를 다음과 같이 설정했습니다.Nothing/null변수를 수동으로 설정하는 함수를 호출했습니다.Nothing/null널 위해서.

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

예를 들어 다음과 같습니다.

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

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

.NET 런타임은 위의 코드와 같이 인스턴스화되지 않은 것에 대해 액션을 수행하려고 하면 NullReferenceException을 느려집니다.

Argument Null Exception과 비교하여 전달되는 것이 늘이 아니라고 메서드가 예상할 경우 일반적으로 방어 수단으로 느려집니다.

자세한 내용은 C# NullReferenceExceptionNullParameter참조하십시오.

업데이트 C#8.0, 2019: 무효 참조 유형

C#8.0에는 null 가능한 참조 유형과 null 불가능한 참조 유형이 도입되었습니다.따라서 NullReferenceException을 피하기 위해 null 가능한 참조 유형만 체크해야 합니다.


참조 유형을 초기화하지 않고 해당 속성 중 하나를 설정 또는 읽으려면 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이 느려지는 이유를 완전히 이해하려면 값 유형과 [reference type][3]의 차이를 알아야 합니다.

따라서 값 유형을 다루는 경우 NullReferenceExceptions는 발생할 수 없습니다., 레퍼런스 타입을 취급할 때는 주의가 필요합니다!

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

참조 유형(이러한 유형은 반드시 확인해야 함):

  • 역학
  • 물건
  • 스트링

값 유형(이러한 유형은 무시해도 됩니다)

  • 수치형
  • 일체형
  • 부동 소수점 유형
  • 십진수
  • 부울
  • 사용자 정의 구조

또 다른 경우는NullReferenceExceptionscan occurrent는 연산자의 (적절한) 사용입니다.

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

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

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

여기서,Book그리고.Car호환되지 않는 유형입니다.Car로 변환/주조할 수 없다Book이 캐스팅이 실패하면as돌아온다null.사용.mybook이 후에 a가 발생한다.NullReferenceException.

일반적으로 깁스를 하거나as다음과 같습니다.

유형 변환이 항상 성공하기를 기대하는 경우(즉,어떤 오브젝트가 선행되어야 하는지 알고 있습니다). 그런 다음 깁스를 사용해야 합니다.

ComicBook cb = (ComicBook)specificBook;

유형을 알 수 없지만 특정 유형으로 사용하려는 경우 다음을 사용하십시오.as:

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

null 값 참조를 포함하는 개체를 사용하고 있습니다.즉, null 예외를 두는 것입니다.이 예에서는 문자열 값이 null이며 문자열의 길이를 확인할 때 예외가 발생했습니다.

예:

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

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

처리되지 않은 예외:

System.NullReferenceException:개체 참조가 개체의 인스턴스로 설정되지 않았습니다.프로그램에 등록해 주세요.메인()

NullReferenceExceptions의 원인 및 이러한 예외를 회피/수정하기 위한 접근법은 다른 답변에서도 다루어졌지만, 많은 프로그래머들이 아직 배우지 못한 것은 개발 중에 이러한 예외를 독립적으로 디버깅하는 방법입니다.

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


먼저 올바른 오류가 검출되는지 확인합니다('시스템'의 브레이킹을 허용하는 방법 참조).VS2010의 NullReferenceException'은?메모1

그런 다음 Start with Debugging(F5) 또는 Attach [VS Debugger]를 Running Process에 연결합니다.경우에 따라서는 를 사용하면 디버거를 시작할 수 있습니다.

여기서 NullReferenceException이 느려지면(또는 처리되지 않음) 예외 발생 행에서 디버거가 중지됩니다(위의 규칙 설정을 기억하십니까?).경우에 따라서는, 에러를 발견하기 쉬울 수 있습니다.

예를 들어, 다음 행에서 예외를 일으킬 수 있는 유일한 코드는 다음과 같습니다.myString는 늘로 평가됩니다.워치 창을 보거나 즉시 에서 식을 실행하여 확인할 수 있습니다.

var x = myString.Trim();

다음과 같은 보다 고도의 경우 위의 기술(와치 또는 즉시 윈도) 중 하나를 사용하여 식을 검사하여 다음 중 하나를 확인해야 합니다.str1null 또는 if의 경우str2null 이었습니다.

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

예외의 위치를 찾은 후에는 보통 null 값이 [잘못] 도입된 위치를 찾기 위해 역추론을 하는 것은 간단한 일입니다.

예외의 원인을 이해하는 데 필요한 시간을 갖습니다.null 표현식을 검사합니다.이러한 null 식이 발생할 수 있는 이전 식을 검사하십시오.중단점을 추가하고 필요에 따라 프로그램을 진행합니다.디버거를 사용합니다.


1 Break on Strows가 너무 공격적이고 디버거가 의 NPE 상에서 정지하는 경우.NET 또는 서드파티 라이브러리의 Break on User-Unhandled를 사용하여 검출된 예외를 제한할 수 있습니다.또한 VS2012에서는 Just My Code도 도입하고 있습니다.이것도 유효하게 하는 것을 추천합니다.

[ Just My Code ]를 유효하게 해 디버깅 하는 경우는, 동작이 약간 다릅니다.Just My Code를 활성화하면 디버거는 My Code 외부에서 발생하며 My Code를 통과하지 않는 First-Chance Common Language Runtime(CLR) 예외를 무시합니다.

사이먼 MOUR MOU는 다음과 같다.

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

대화(캐스트)에서 대화(캐스트) object(또는 수업 중 하나)System.ValueType또는System.Enum, 또는 인터페이스 유형)에서 값 유형(또는 인터페이스 유형)로Nullable<>) 자체에서NullReferenceException.

다른 방향에서 복싱 대화를 나누다.Nullable<>- 아니, 아니에요! - 왜요?HasValue…과 동일하다false 참조 타입에 대해서, a를 지정할 수 있습니다.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.aspx 웹 폼의 codebehind 클래스가 Contact이고 엔티티 이름이 Contact라고 가정합니다.

다음 코드는 컨텍스트를 호출할 때 NullReferenceException을 슬로우합니다.Save Changes()

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

완전성을 위해 Data Context 클래스

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

엔티티 클래스에 문의합니다.엔티티 클래스가 부분 클래스인 경우도 있으므로 다른 파일에서도 확장할 수 있습니다.

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

이 오류는 엔티티 클래스와 codebehind 클래스가 모두 같은 네임스페이스에 있는 경우에 발생합니다.이 문제를 해결하려면 Contact.aspx의 엔티티 클래스 또는 codebehind 클래스의 이름을 변경합니다.

이유는 아직 확실하지 않다.그러나 엔티티 클래스 중 하나가 시스템을 확장합니다.Web.UI.Page 이 에러가 발생합니다.

자세한 내용은 DbContext.saveChanges()의 NullReferenceException을 참조하십시오.

이 예외를 받을 수 있는 또 다른 일반적인 경우로는 유닛 테스트 중 수업을 조롱하는 경우가 있습니다.사용되는 조롱 프레임워크에 관계없이 클래스 계층의 모든 적절한 수준이 적절하게 조롱되는지 확인해야 합니다.특히 의 모든 속성은HttpContext테스트 대상 코드에 의해 참조되는 것은 조롱해야 한다.

자세한 예는 "커스텀 Authorization Attribute 테스트 시 던지는 NullReferenceException"을 참조하십시오.

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

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

'어떻게 하면 좋을까'에 대해서는 여러 가지 답이 있을 수 있다.

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

, 클래스 불변수는 클래스 내에서 정상적인 사용 시 위반되지 않는 제약조건이 있음을 보증합니다(따라서 클래스가 일관되지 않은 상태가 되지 않습니다).전제조건은 함수/메서드에 입력으로 주어진 데이터가 일부 제약조건을 따라야 하며 이를 위반해서는 안 된다는 것을 의미하며, 사후조건은 함수/메서드 출력이 해당 제약조건을 위반하지 않고 다시 설정 제약조건을 따라야 한다는 것을 의미합니다.버그 프리 프로그램 실행 중에는 계약 조건을 위반해서는 안 됩니다.따라서 디버깅모드에서는 설계 체크가 실행 중이고 릴리즈에서는 비활성화되어 있기 때문에 개발된 시스템퍼포먼스를 최대화할 수 있습니다.

이렇게 하면,NullReferenceException제약 조건 세트 위반의 결과인 사례.예를 들어 객체 속성을 사용하는 경우X그 메서드 중 하나를 호출하려고 합니다.X값이 null입니다.이것에 의해,NullReferenceException:

public X { get; set; }

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

단, 메서드 전제조건으로 "property X must null value"를 설정하면 앞에서 설명한 시나리오를 방지할 수 있습니다.

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

따라서 에 대한 코드 계약 프로젝트가 존재합니다.NET 어플리케이션

또는 청부설계를 이용하여 계약에 의한 설계를 적용할 수 있다.

업데이트: 이 용어는 Bertrand Meyer의 에펠 프로그래밍 언어 설계와 관련하여 만들어졌다는 것을 언급할 가치가 있습니다.

A NullReferenceExceptionnull 객체의 Properties에 액세스하려고 할 때 또는 문자열 값이 비어 있을 때 문자열 메서드에 액세스하려고 할 때 느려집니다.

예를 들어 다음과 같습니다.

  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 
    

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가 앰퍼샌드와 브래킷을 잘못 읽었기 때문인 것 같습니다.

어떻게 할 수 있죠?

여기에서는 늘 참조의 정의와 디버깅 방법을 설명하는 좋은 답변이 많이 있습니다.그러나 이 문제를 예방하거나 최소한 더 쉽게 잡을 수 있는 방법은 거의 없다.

인수 확인

예를 들어 메서드는 서로 다른 인수를 체크하여 null인지 여부를 확인하고 다음 인수를 슬로우할 수 있습니다.ArgumentNullException이 목적을 위해 작성된 예외입니다.

의 컨스트럭터ArgumentNullException는 파라미터와 메시지의 이름을 인수로 사용하므로 개발자에게 문제가 무엇인지 정확하게 알릴 수 있습니다.

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

도구 사용

도움이 되는 라이브러리도 몇 개 있습니다.예를 들어 "Resharper"는 코드를 작성하는 동안 경고를 제공할 수 있습니다. 특히 해당 속성을 사용하는 경우 다음과 같습니다.Not Null Attribute(속성 없음)

다음과 같은 구문을 사용하는 "Microsoft 코드 계약"이 있습니다.Contract.Requires(obj != null)실행 시 및 컴파일 검사를 수행할 수 있습니다.코드 계약 소개

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

public void DoSometing([NotNull] obj)

이를 통해 Post Sharp를 빌드 프로세스의 일부로 만듭니다.obj실행 시 늘이 체크됩니다.자세한 내용은 'Post Sharp'의 특수한 체크입니다.

플레인 코드 솔루션

또는 언제든지 기존의 코드를 사용하여 자신의 접근 방식을 코드화할 수 있습니다.예를 들어 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유형 객체입니다.Country라고 불리는 속성을 가지고 있다.State기타 등등.한다면country,State,County, 또는Citynull그리고나서address will be무효. Therefore you only have to check whether주소.is특수한 순서입니다.

이것은 훌륭한 기능이지만, 정보가 적습니다.그것은 4개 중 어느 것이 무효인지 명확히 하지 않는다.

Nullable과 같은 빌트인?

C#은 의 줄임말이다.Nullable<T>, 다음과 같은 타입 뒤에 물음표를 붙이면, 무효로 할 수 있습니다.int?.

C#에게 이런 게 있었으면 좋겠어요.NotNull<T>위의 구조에는 다음과 같은 느낌표(!)가 붙어 있습니다.public void WriteName(Person! person).

수정할 수 있습니다.NullReferenceExceptionC# 6에서 Null-conditional 연산자를 사용하여 깔끔하게 처리하며 Null 체크를 처리하기 위해 코드를 적게 씁니다.

멤버 액세스(?) 또는 인덱스(?[) 조작을 실행하기 전에 늘을 테스트하기 위해 사용됩니다.

  var name = p?.Spouse?.FirstName;

이는 다음과 같습니다.

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

그 결과 p가 null이거나 p가 null일 때 이름이 null이 됩니다.p.Spousenull 입니다.

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

상세한 것에 대하여는, 다음을 참조해 주세요.Null-conditional 연산자

흥미롭게도, 이 페이지의 답변 중 두 가지 가장 중요한 경우를 언급하는 답변은 없습니다.

Edge 케이스 1: 사전 동시 액세스

의 범용 딕셔너리.NET은 스레드 세이프가 아니기 때문에, 경우에 따라서는,NullReference또는 (더 자주)KeyNotFoundException두 개의 동시 스레드에서 키에 액세스하려고 할 때.이 경우 예외는 상당히 오해를 불러일으킬 수 있습니다.

Edge Case #2: 안전하지 않은 코드

만약 a가NullReferenceException에 의해 던져지다unsafe코드, 포인터 변수를 보고 체크할 수 있습니다.IntPtr.Zero뭐 그런 거.이는 동일한 사항("늘 포인터 예외")이지만 안전하지 않은 코드에서는 변수가 값 유형/어레이 등에 캐스팅되는 경우가 많은데, 값 유형이 이 예외를 어떻게 던질 수 있는지 궁금해하며 벽에 머리를 부딪힙니다.

(필요한 경우를 제외하고 안전하지 않은 코드를 사용하지 않는 또 다른 이유)

Edge Case #3: 프라이머리 모니터와 다른 DPI 설정을 가진 세컨더리 모니터를 사용한 Visual Studio 멀티 모니터 설정

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

문제를 재현하는 방법: 툴박스에서 프라이머리 모니터와 다른 DPI 설정을 가진 비프라이머리 모니터의 Windows 폼으로 컴포넌트를 드래그하면 "Object reference not set to object instance of object"라는 팝업이 나타납니다. 스레드에 따르면, 이 문제는 꽤 오랫동안 알려져 왔고, 집필 시점에서는 아직 수정되지 않았습니다.

"Object reference not set to a instance of object" 오류 행은 인스턴스 개체를 개체 참조에 할당하지 않았으며 여전히 해당 개체의 속성/메서드에 액세스 중임을 나타냅니다.

예를 들어, 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;
     }
}

간단히 말하면:

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

그럼 어떻게 대처해야 할까요?

  1. 디버깅하고 디버거가 고장나도록 합니다.망가진 변수로 바로 이동하게 될 거야이제 당신의 임무는 간단히 이 문제를 해결하는 것입니다.적절한 장소에서 새로운 키워드를 사용합니다.

  2. 객체가 존재하지 않아 일부 데이터베이스 명령에서 발생한 경우 null 검사를 수행하여 처리하기만 하면 됩니다.

    if (i == null) {
        // Handle this
    }
    
  3. 가장 어려운 것은... GC가 이미 객체를 수집했다면...이 문제는 일반적으로 문자열을 사용하여 개체를 찾으려는 경우에 발생합니다.즉, 오브젝트의 이름으로 검색하면 GC가 이미 오브젝트를 청소했을 가능성이 있습니다.이것은 찾기 어려우므로 큰 문제가 될 것입니다.이 문제를 해결하는 더 좋은 방법은 개발 프로세스 중에 필요한 경우 늘 체크를 수행하는 것입니다.이렇게 하면 시간이 많이 절약됩니다.

이름으로 찾는다는 것은 문자열을 사용하여 FIndObjects를 사용할 수 있는 프레임워크가 있다는 것을 의미하며 코드는 다음과 같습니다.Find Object("ObjectName");

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 클래스는 인스턴스화되지 않습니다.따라서 스테이트먼트가 s일 때.GetFullName()이 실행되면 NullReferenceException이 느려집니다.

말 그대로 NullReferenceExeption을 수정하는 가장 쉬운 방법은 두 가지입니다.

예를 들어 스크립트를 첨부한 GameObject와 rb(rigidbody)라는 변수가 있는 경우 게임을 시작할 때 이 변수는 null로 시작합니다.따라서 NullReferenceExeption은 컴퓨터에 저장된 데이터가 없기 때문에 표시됩니다.

예를 들어 RigidBody 변수를 사용합니다.실제로 다음과 같은 방법으로 데이터를 쉽게 추가할 수 있습니다.

  1. Add Component > Physical > Rigidbody 를 사용하여 오브젝트에 강체를 추가한 후 스크립트를 열고 입력합니다.rb = GetComponent<Rigidbody>();이 코드 행은 고객님의 환경에서 가장 적합합니다.Start()또는Awake()기능들.
  2. 컴포넌트를 프로그래밍 방식으로 추가하고 다음 코드 행으로 변수를 동시에 할당할 수 있습니다.rb = AddComponent<RigidBody>();

기타 주의사항:Unity에서 오브젝트에 컴포넌트를 추가하고 싶은데 컴포넌트를 추가하는 것을 잊은 경우 다음과 같이 입력합니다.[RequireComponent(typeof(RigidBody))]클래스 선언 위(사용법 아래 공간)

게임을 만들고 즐기세요!

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

그 이유는 파일명을 변경했기 때문에 오래된 파일이 아직 열려 있었기 때문입니다.

이것은 기본적으로 Null 참조 예외입니다.Microsoft가 밝힌 바와 같이-

값이 null인 유형의 멤버에 액세스하려고 하면 NullReferenceException 예외가 느려집니다.

그게 무슨 의미죠?

즉, 가치가 없는 멤버가 특정 작업을 수행하도록 하면 시스템이 메시지를 던지고 다음과 같이 말합니다.

"잠깐만, 그 멤버는 가치가 없기 때문에 당신이 넘겨주는 작업을 수행할 수 없습니다."

예외 자체는 어떤 것이 참조되고 있지만 그 값이 설정되지 않은 것을 나타냅니다.따라서 이는 값 유형이 Null이 아니므로 참조 유형을 사용하는 동안에만 발생함을 나타냅니다.

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

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

위의 코드는 null 값을 사용하여 할당된 단순한 문자열을 나타냅니다.

문자열 str의 길이를 인쇄하려고 하면 "System" 유형의 처리되지 않은 예외가 나타납니다.NullReferenceException' 메시지발생한 것은 멤버스트링이 null을 가리키고 있기 때문에 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가 할당 해제되어 있다는 오류를 발생시킵니다.이것은 변수가 늘 값을 가지거나 아무것도 없음을 나타냅니다.위의 코드에 대한 컴파일러는 변수 obj가 할당 해제되어 있다는 오류를 발생시킵니다.이것은 변수가 늘 값을 가지거나 아무것도 없음을 나타냅니다.

왜 이런 일이 일어나죠?

  • NullReferenceException은 객체의 값을 확인하지 않은 오류로 인해 발생합니다.코드 개발에서는 오브젝트 값을 체크하지 않는 경우가 많습니다.

  • 그것은 또한 우리가 우리의 사물을 인스턴스화하는 것을 잊었을 때 발생한다.null 값을 반환하거나 설정할 수 있는 메서드, 속성, 컬렉션 등을 사용하는 것도 이 예외의 원인일 수 있습니다.

어떻게 피할 수 있을까요?

이 유명한 예외를 회피하는 방법 및 방법은 다음과 같습니다.

  1. 명시적 체크:개체, 속성, 메서드, 어레이 및 수집이 늘인지 확인하는 전통을 지켜야 합니다.이는 if-else if-else 등의 조건문을 사용하여 간단히 구현할 수 있습니다.

  2. 예외 처리:이 예외를 관리하는 중요한 방법 중 하나입니다.단순한 try-catch-finally 블록을 사용하면 이 예외를 제어하고 로그를 유지할 수 있습니다.이것은, 애플리케이션이 실가동 스테이지에 있는 경우에 매우 편리합니다.

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

  4. 디버거:개발자들에게는 디버깅이라는 큰 무기가 있습니다.개발 중에 NullReferenceException이 발생했을 경우 디버거를 사용하여 예외의 소스에 도달할 수 있습니다.

  5. 내장 방식:GetValueOrDefault(), IsNullOr 등의 시스템 메서드WhiteSpace() 및 IsNullor Empty()는 늘을 확인하고 늘 값이 있는 경우 기본값을 할당합니다.

여기에는 이미 많은 좋은 답변들이 있다.블로그에서 예를 들어 좀 더 자세한 설명을 확인하실 수도 있습니다.

이것도 도움이 되었으면 좋겠다!

언급URL : https://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it

반응형