Как определить, создан ли класс (конструктор экземпляра завершен)? - PullRequest
6 голосов
/ 09 сентября 2011

У меня есть базовый класс, у которого есть метод, который выполняется производными классами. Метод вызывается конструктором производного класса и некоторыми методами или свойствами в нем. Мне нужно определить, пришел ли он из конструктора экземпляра этого производного класса или после него (во время выполнения).

Следующий пример объясняет, что мне нужно:

public class Base
{
    public Base()
    {

    }

    protected void OnSomeAction(object sender)
    {
        // if from derived constructor EXIT, else CONTINUE
    }
}

public class Derived : Base
{
    public void Raise()
    {
        base.OnSomeAction(this); // YES if not called by constructor
    }

    public Derived()
    {
        base.OnSomeAction(this); // NO
        Raise(); // NO
    }
}

class Program
{
    static void Main(string[] args)
    {
        var c = new Derived(); // NO (twice)
        c.Raise(); // YES
    }
}

Проблема в том, что я не могу изменить подпись или аргументы, потому что я не могу изменить производные классы. По сути, я подумал о том, чтобы определить, полностью ли создан производный класс (отправитель).

Итак, реализация такая, как есть. Я не могу делать изменения в базовом классе, которые нарушают производные классы. Я могу вносить изменения только в базовый класс: /

Это возможно каким-то образом, хорошо или нет? К сожалению, приветствуется даже некоторая магия отражения или подобный хакерский подход, так как это необходимо: /.

Спасибо!

Ответы [ 4 ]

7 голосов
/ 09 сентября 2011

Возможно ли это каким-то образом ...

Да

хорошо или нет?

Нет.Но вы уже знали это.

Тем не менее, вот один из способов сделать это.

protected void OnSomeEvent( object sender, EventArgs e )
{
    var trace = new StackTrace();
    var frames = trace.GetFrames();

    for ( int idx = 0; idx < frames.Length; idx++ )
    {
        MethodBase method;

        method = frames[idx].GetMethod();
        if ( method.ReflectedType == typeof(Derived) && method.IsConstructor )
        {
            return;
        }
    }
    /* Perform action */
}

source

3 голосов
/ 09 сентября 2011

Хороший, чистый, правильный путь - нет!Боюсь, что нет.

Хакерский путь, который, несомненно, приведет к боли и страданию. Возможно.

Поместите это в ваш обработчик OnSomeEvent:

var whoCalledMe = new StackTrace().GetFrame(1).GetMethod().Name;

будет.ctor при вызове из конструктора или Main при вызове из метода Raise.

Пример в реальном времени: http://rextester.com/rundotnet?code=DBRLC84297

0 голосов
/ 09 сентября 2011

Это странная проблема, не в состоянии изменить производное, но может изменить базу? А?

Вот очень простое решение (я чувствую себя грязным):

public class Base
{
    private event EventHandler SomeEvent;
    private int initCount = 0;

    public Base()
    {
    }

    protected void OnSomeEvent(object sender, EventArgs e)
    {
        // if from derived constructor EXIT
        switch (initCount)
        {
            case 0:
                initCount += 1;
                Console.WriteLine("NO");
                return;
            case 1:
                initCount += 1;
                this.SomeEvent += new EventHandler(OnSomeEvent);
                Console.WriteLine("NO");
                return;
        }
        //  else CONTINUE
        Console.Write("YES");
    }
}
0 голосов
/ 09 сентября 2011

Я интерпретирую ваши (очень суровые!) Ограничения как слова, что вы не можете изменять сигнатуры методов и, возможно, не можете добавлять поля экземпляров, но вы будете разрешать изменения кода и статические поля. Если это так, мой подход предполагает установку статической переменной fromDerivedConstructor и ее тестирование в зависимости от ситуации. (Переменная сделана поточно-статической для того, чтобы код был потокобезопасным. Приведенная ниже программа печатает

NO
NO
YES

по запросу: -)

using System;
using System.Diagnostics;

namespace ConsoleApplication33 {
  public class Base {
    [ThreadStatic]
    protected static bool fromDerivedConstructor;

    public Base() {}

    protected void OnSomeAction(object sender) {
      // if from derived constructor EXIT, else CONTINUE
      if(fromDerivedConstructor) {
        Debug.WriteLine("NO");
        return;
      }
      Debug.WriteLine("YES");
    }
  }

  public class Derived : Base {
    public void Raise() {
      base.OnSomeAction(this); // YES if not called by constructor
    }

    public Derived() {
      fromDerivedConstructor=true;
      try {
        base.OnSomeAction(this); // NO
        Raise(); // NO
      } finally {
        fromDerivedConstructor=false;
      }
    }
  }

  internal class Program {
    private static void Main(string[] args) {
      var c=new Derived(); // NO (twice)
      c.Raise(); // YES
    }
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...