У меня есть класс Abstract и класс Derived.Абстрактный класс определяет абстрактное свойство с именем Message.В производном классе свойство реализуется путем переопределения абстрактного свойства.Конструктор производного класса принимает строковый аргумент и присваивает его свойству 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);
}
}
Я нашел несколько других вопросов об этом предупреждении, но в этих ситуациях есть реальный вызов метода.Например, в этом вопросе ответ Мэтта Хауэлса содержит пример кода.Я повторю это здесь для простоты справки.
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());
}
}
Мэтт не описывает, при какой ошибке появится предупреждение, но я предполагаю, что это будет при вызове DoSomething в конструкторе Parent.В этом примере я понимаю, что подразумевается под вызываемым виртуальным членом.Вызов члена происходит в базовом классе, в котором существует только виртуальный метод.
В моей ситуации, однако, я не понимаю, почему присвоение значения Message
будет вызовом виртуального члена.И вызов, и реализация свойства Message определены в производном классе.
Хотя я могу избавиться от ошибки, сделав свой производный класс sealed
, я хотел бы понять, почему эта ситуацияв результате выдается предупреждение.
Обновление Основываясь на ответе Бретта, я приложил все усилия, чтобы создать ChildClass, производный от DerivedClass, который в конечном итоге приведет к исключению.Вот что я придумал:
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 в программе, подобной этой:
internal class Program {
private static void Main() {
var childClass = new ChildClass();
childClass.PrintMessage();
}
}
Вы получите исключение NullReferenceException при создании объекта ChildClass.Исключение будет вызвано попыткой ChildClass использовать _foo.ToUpper()
, так как _foo
еще не инициализирован.