필드 이니셜 라이저는 비 정적 필드, 메서드 또는 속성을 참조 할 수 없습니다.


96

클래스가 있는데 다른 클래스에서 사용하려고하면 아래와 같은 오류가 발생합니다.

using System;
using System.Collections.Generic;
using System.Linq;

namespace MySite
{
    public class Reminders
    {
        public Dictionary<TimeSpan, string> TimeSpanText { get; set; }

        // We are setting the default values using the Costructor
        public Reminders()
        {
            TimeSpanText.Add(TimeSpan.Zero, "None");
            TimeSpanText.Add(new TimeSpan(0, 0, 5, 0), "5 minutes before");
            TimeSpanText.Add(new TimeSpan(0, 0, 15, 0), "15 minutes before");
            TimeSpanText.Add(new TimeSpan(0, 0, 30, 0), "30 minutes before");
            TimeSpanText.Add(new TimeSpan(0, 1, 0, 0), "1 hour before");
            TimeSpanText.Add(new TimeSpan(0, 2, 0, 0), "2 hours before");
            TimeSpanText.Add(new TimeSpan(1, 0, 0, 0), "1 day before");
            TimeSpanText.Add(new TimeSpan(2, 0, 0, 0), "2 day before");
        }

    }
}

다른 클래스에서 클래스 사용

class SomeOtherClass
{  
    private Reminders reminder = new Reminders();
    // error happens on this line:
    private dynamic defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)]; 
    ....

오류 (CS0236) :

A field initializer cannot reference the nonstatic field, method, or property

왜 발생하고 어떻게 해결합니까?

답변:


147

이 줄 :

private dynamic defaultReminder = 
                          reminder.TimeSpanText[TimeSpan.FromMinutes(15)];

인스턴스 변수를 사용하여 다른 인스턴스 변수 를 초기화 할 수 없습니다 . 왜? 컴파일러는이를 다시 정렬 할 수 있기 때문에 - 보장은 없습니다 reminder전에 초기화됩니다 defaultReminder위의 라인은, 그래서 수도 을 던져 NullReferenceException.

대신 다음을 사용하십시오.

private dynamic defaultReminder = TimeSpan.FromMinutes(15);

또는 생성자에서 값을 설정하십시오.

private dynamic defaultReminder;

public Reminders()
{
    defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)]; 
}

이 컴파일러 오류에 대한 자세한 내용은 MSDN- Compiler Error CS0236에 있습니다.


3
Java는 이러한 종류의 구성에 대해 더 '관용'합니다. 그것이 좋은 것인지 모르겠다. stackoverflow.com/questions/1494735/…
Wouter Schut 2015

32
아니요, 컴파일러는 이니셜 라이저를 재정렬 할 수 없습니다. C # 언어 사양은 "10.5.5.2 인스턴스 필드 초기화"섹션에 다음과 같이 명시되어 있습니다 . 변수 이니셜 라이저는 클래스 선언에 나타나는 텍스트 순서로 실행됩니다. 이것은 "10.11.2 인스턴스 변수 이니셜 라이저"에서도 반복됩니다 . 변수 이니셜 라이저는 클래스 선언에 나타나는 텍스트 순서로 실행됩니다. 그래서 당신의 설명이 잘못되었습니다. 순서는 고정되어 있습니다. 이것이 허용되지 않는 이유는 C #의 디자이너가 그런 식으로 원했기 때문입니다.
Jeppe Stig Nielsen

(만의 경우 partial class여러 파일에서 "부품"을 명확 필드 초기화의 순서는, 그러나 그것은 간다 static아니라 필드!)
Jeppe의 Stig 닐슨

@WouterSchut 링크 한 스레드는 Java에 관한 것이 아닙니다! C #에 관한 것이지만 static인스턴스 필드 대신 필드가 있습니다.
Jeppe Stig Nielsen

2
@Andrew 전혀 사실이 아닙니다. 나쁜 관행을 금지하기 위해 많은 결정이 내려졌습니다. 이론적으로 구현할 수 있지만 일부는 경고로 보호되고 일부는 일반 오류입니다. 그리고 나는 이것이 이러한 경우 중 하나라고 생각합니다 ... 표준이 그것이 속편이라고 말하더라도 숙련 된 개발자조차도 (표준을 검색하지 않고) 자신있게 말하지 않을 것입니다.
Tomer W

22

해당 코드를 클래스 생성자에 넣어야합니다.

private Reminders reminder = new Reminders();
private dynamic defaultReminder;

public YourClass()
{
    defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)];
}

그 이유는 하나의 인스턴스 변수를 사용하여 필드 이니셜 라이저를 사용하여 다른 변수를 초기화 할 수 없기 때문입니다.


10

이렇게 사용할 수 있습니다

private dynamic defaultReminder => reminder.TimeSpanText[TimeSpan.FromMinutes(15)]; 

11
Stack Overflow에 오신 것을 환영합니다! 이 코드 스 니펫은 질문을 해결할 수 있지만 설명을 포함하면 게시물의 품질을 향상시키는 데 큰 도움이됩니다. 미래에 독자를 위해 질문에 답하고 있으며 해당 사용자는 코드 제안 이유를 모를 수 있습니다. 코드와 설명의 가독성을 떨어 뜨리므로 설명 주석으로 코드를 혼잡하게 만들지 마십시오!
jmattheis

3
= 대신 =>를 사용하여 속성으로 만듭니다.
Vincent

3
using =>은 실제 값을 설정하지 않지만 defaultReminder액세스 할 때마다 코드를 실행하므로이 기술을 사용하는 데주의해야합니다 . 이는 의도 된 것이 아니며 성능에 부정적인 영향을 미치거나 GC 등에 대해 원치 않는 압력을 생성 할 수 있습니다.
Smilediver

4

private dynamic defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)];필드 이니셜 라이저이고 먼저 실행됩니다 (이니셜 라이저가없는 필드가 기본값으로 설정되기 전과 호출 된 인스턴스 생성자가 실행되기 전). 이니셜 라이저가없는 인스턴스 필드는 모든 인스턴스 필드 이니셜 라이저가 완료된 후에 만 ​​유효한 (기본값) 값을 갖습니다. 초기화 순서로 인해 인스턴스 생성자가 마지막으로 실행되기 때문에 초기화 프로그램이 실행되는 순간 인스턴스가 생성되지 않습니다. 따라서 컴파일러는 클래스 인스턴스가 완전히 생성되기 전에 인스턴스 속성 (또는 필드)을 참조 할 수 없습니다. 이는 인스턴스 변수에 대한 모든 액세스가 reminder암시 적으로 인스턴스 ( this)를 참조 하여 컴파일러에게 사용할 인스턴스의 구체적인 메모리 위치를 알려주기 때문입니다.

이것이 this인스턴스 필드 이니셜 라이저에서 허용되지 않는 이유이기도합니다 .

인스턴스 필드의 변수 이니셜 라이저는 생성중인 인스턴스를 참조 할 수 없습니다. 따라서 변수 이니셜 라이저가 simple_name을 통해 인스턴스 멤버를 참조하는 것은 컴파일 타임 오류이므로 변수 이니셜 라이저에서 이것을 참조하는 것은 컴파일 타임 오류입니다 .

인스턴스 필드 이니셜 라이저가 실행 되기 전에 초기화가 보장되는 유일한 형식 멤버 는 클래스 (정적) 필드 이니셜 라이저와 클래스 (정적) 생성자 및 클래스 메서드입니다. 정적 멤버는 인스턴스 독립적이므로 언제든지 참조 할 수 있습니다.

class SomeOtherClass
{
  private static Reminders reminder = new Reminders();

  // This operation is allowed,
  // since the compiler can guarantee that the referenced class member is already initialized
  // when this instance field initializer executes
  private dynamic defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)];
}

이것이 인스턴스 필드 이니셜 라이저가 클래스 멤버 (정적 멤버) 만 참조 할 수있는 이유입니다. 이 컴파일러 초기화 규칙은 결정적 유형 인스턴스화를 보장합니다.

자세한 내용은이 문서를 권장합니다 : Microsoft Docs : Class declarations .

즉, 다른 인스턴스 멤버를 참조하여 해당 값을 초기화하는 인스턴스 필드는 인스턴스 생성자에서 초기화하거나 참조 된 멤버를 선언해야합니다 static.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.