2011-01-07 4 views
4

나는 Abstract 클래스와 Derived 클래스를 가진다. 추상 클래스는 Message라는 추상 속성을 정의합니다. 파생 클래스에서이 속성은 abstract 속성을 재정 의하여 구현됩니다. 파생 클래스의 생성자는 문자열 인수를 사용하여 Message 속성에 할당합니다. Resharper에서이 할당은 "생성자에서의 가상 멤버 호출"이라는 경고로 이어진다.속성에 값을 할당 할 때 생성자에서 가상 멤버 호출

AbstractClass이 정의가 있습니다

public abstract class AbstractClass { 
    public abstract string Message { get; set; } 

    protected AbstractClass() {} 

    public abstract void PrintMessage(); 
} 

을 그리고 DerivedClass은 다음과 같다 :

using System; 

public class DerivedClass : AbstractClass { 
    private string _message; 

    public override string Message { 
     get { return _message; } 
     set { _message = value; } 
    } 

    public DerivedClass(string message) { 
     Message = message; // Warning: Virtual member call in a constructor 
    } 

    public DerivedClass() : this("Default DerivedClass message") {} 

    public override void PrintMessage() { 
     Console.WriteLine("DerivedClass PrintMessage(): " + Message); 
    } 
} 
나는이 경고에 대한 몇 가지 다른 질문을 발견했다, 그러나 그 상황에서 실제 통화가

방법에. 예를 들어 this question에서 Matt Howels의 답변에는 몇 가지 샘플 코드가 들어 있습니다. 나는 여기서 쉽게 반복 할 것이다.

class Parent { 
    public Parent() { 
     DoSomething(); 
    } 
    protected virtual void DoSomething() {}; 
} 

class Child : Parent { 
    private string foo; 
    public Child() { foo = "HELLO"; } 
    protected override void DoSomething() { 
     Console.WriteLine(foo.ToLower()); 
    } 
} 

매트는 경고가 나타납니다 어떤 오류에 대해서는 설명하지 않습니다,하지만 난 그게 부모 생성자 해봐요 호출에있을 것입니다 있으리라 믿고있어. 이 예제에서는 가상 멤버가 호출된다는 의미를 이해합니다. 멤버 메서드 호출은 가상 메서드 만있는 기본 클래스에서 발생합니다.

그러나 내 상황에서는 Message에 값을 할당하면 가상 회원을 호출하는 이유가 표시되지 않습니다. Message 속성의 호출과 구현은 모두 파생 클래스에서 정의됩니다.

내 파생 클래스 sealed을 작성하여 오류를 제거 할 수 있지만이 상황이 경고의 원인이되는 이유를 알고 싶습니다. 브렛의 답변에 따라

업데이트 , 내가 궁극적으로 예외가 발생합니다 DerivedClass에서 파생 된 ChildClass에를 만들기 위해 최선을 다했다.

using System; 

public class ChildClass : DerivedClass { 
    private readonly string _foo; 

    public ChildClass() : base("Default ChildClass Message") { 
     _foo = "ChildClass foo"; 
    } 

    public override string Message { 
     get { return base.Message; } 
     set { 
      base.Message = value; 
      Console.WriteLine(_foo.ToUpper() + " received " + value); 
     } 
    } 
} 

은 물론 오프는 메시지 세터에 _foo를 사용하는 어리석은 조금,하지만 요점은 ReSharper에서이 클래스 잘못 아무것도 표시되지 않는다는 것입니다 : 이것은 내가 생각 해낸 것입니다.

그러나,이 같은 프로그램에서 ChildClass에 사용하려고하면

다음 ChildClass에 객체를 생성 할 때

internal class Program { 
    private static void Main() { 
     var childClass = new ChildClass(); 
     childClass.PrintMessage(); 
    } 
} 

당신은 NullReferenceException이를 얻을 수 있습니다. ChildClass가 _foo.ToUpper()을 사용하려고 시도했을 때 예외가 발생하고 _foo은 초기화되지 않았으므로 예외가 발생합니다. 하는 것이 DerivedClass에서의 ctor에서 ChildClass에 메시지에서 코드를 호출 할 수의 관점, 그리고 ChildClass 인스턴스는 초기화 완전하지 않을 수 있습니다 -

답변

6

메시지 속성이 class ChildClass : DerivedClass 오버라이드 (override) 할 수 있기 때문이다.

귀하의 DerivedClass을 봉인하여 문제를 해결하는 이유는 그것이 상속 될 수 없기 때문입니다.

+0

이상합니다. DerivedClass에서 가상 클래스가 아닌 경우 ChildClass가 내 Message 속성을 재정의 할 수 있습니까? 암시 적으로 오버 라이팅이 가상입니까? – comecme

+1

구현을 재정의하면 가상 멤버라는 사실을 변경하지 않습니다. 그래, 네. – Brett

+2

* 메소드 *를 'sealed'로 표시 할 수 있습니다. 즉, 아무도 하위 클래스에서 재정의 할 수 없으므로 더 이상 가상이 아닙니다. 그것도 오류를 제거해야합니다. –

관련 문제