Метод C # из производного класса в качестве делегата в базовом конструкторе - PullRequest
8 голосов
/ 21 февраля 2011

Почему следующий C # не разрешен?Существует ли правильный обходной путь?

public class Base
{
    public Base(Func<double> func) { }
}

public class Derived : Base
{
    public Derived() : base(() => Method()) <-- compiler: Cannot access non-static method 'Method' in static context
    {
    }

    public double Method() { return 1.0; }
}

Ответы [ 5 ]

10 голосов
/ 21 февраля 2011

Он фактически ссылается на «this» в аргументах базового конструктора, чего вы не можете сделать.

Если вашему делегату действительно не нужен доступ к this (чего не делает ваш пример)т) вы можете просто сделать это статичным.Вы также можете использовать преобразование группы методов, чтобы сделать его проще:

public class Base
{
    public Base(Func<double> func)
    {
        double result = func();
    }
}

public class Derived : Base
{
    public Derived() : base(Method)
    {
    }

    public static double Method() { return 1.0; }
}

Если вам нужно нужно использовать «this», вы можете:

  • Сделайте его виртуальным методом вместо вызова делегата
  • Сделайте его статическим методом, который принимает соответствующий экземпляр, например

    public class Base
    {
        public Base(Func<Base, double> func)
        {
            double result = func(this);
        }
    }
    
    public class Derived : Base
    {
        public Derived() : base(x => Method(x))
        {
        }
    
        private static double Method(Base b) 
        {
            // The documentation would state that the method would only be called
            // from Base using "this" as the first argument
            Derived d = (Derived) b;
        }
    }
    
1 голос
/ 16 октября 2015

Другое решение этой проблемы - просто отложить инициализацию делегата для производного класса:

public class Base {
   protected Func<double> DoubleFunc { get; set; }

   protected Base() {
      // defer initialization by not setting DoubleFunc
      // or another possibility is to set it to a dummy function:
      DoubleFunc = () => 0;
   }

   public Base(Func<double> func) {
      DoubleFunc = func;
   }
}

public class Derived : Base {
   public Derived() {
      DoubleFunc = Method;
   }

   public double Method() { return 1.0; }
}
1 голос
/ 21 февраля 2011

Обычно вы получаете ошибку компилятора, потому что вы ссылаетесь на метод экземпляра Method без экземпляра вашего класса Derived. При вызове base конструктор еще не завершен, и у вас еще нет экземпляра вашего класса. Если бы вы сделали Method static, это бы прекрасно работало.

0 голосов
/ 21 февраля 2011

Обходной путь должен был бы сделать Method () статическим методом.

Я не могу объяснить технические причины, почему это не работает, но по сути вы пытаетесь вызвать метод для экземпляра, который еще не существует. Как это могло сработать?

0 голосов
/ 21 февраля 2011

Вы пытались сделать Method() статическим, как указывает компилятор?Проблема в том, что экземпляр Derived недоступен до тех пор, пока не вернется конструктор, поэтому вы не можете вызвать метод экземпляра для него.

...