Подтвердить что ты не робот

База конструктора вызовов после выполнения кода

Скажем, у нас есть класс A и класс B. ClassB расширяет класс A. (ClassB: ClassA)

Теперь скажем, что всякий раз, когда я создаю экземпляр класса ClassB, я хотел бы запустить какой-нибудь случайный код и только потом вызвать "base" для доступа к конструктору ClassA.

Как

class ClassA
{
    public ClassA()
    {
        Console.WriteLine("Initialization");
    }  
}

class ClassB : ClassA
{
    public ClassB() //: base() 
    {
        // Using :base() as commented above, I would execute ClassA ctor before                                                         //          Console.WriteLine as it is below this line... 
        Console.WriteLine("Before new");
        //base() //Calls ClassA constructor using inheritance
        //Run some more Codes here...
    }
}

На языке программирования, с которым я обычно работаю, я могу это сделать, просто позвонив super() после Console.WriteLine(); Но я не могу сделать это на С#. Есть ли другой синтаксис или другой способ сделать это?

4b9b3361

Ответ 1

Там хакерский способ сделать это с помощью инициализатора переменной экземпляра:

using System;

class ClassA
{
    public ClassA()
    {
        Console.WriteLine("Initialization");
    }  
}

class ClassB : ClassA
{
    private readonly int ignoreMe = BeforeBaseConstructorCall();

    public ClassB()
    {
    }

    private static int BeforeBaseConstructorCall()
    {
        Console.WriteLine("Before new");
        return 0; // We really don't care
    }
}

class Test
{
    static void Main()
    {
        new ClassB();
    }    
}

Менее опасный способ сделать это - переосмыслить, как вы начинаете с ClassB. Вместо того, чтобы клиенты вызывали конструктор напрямую, предоставьте им статический метод:

public static ClassB CreateInstance()
{
    Console.WriteLine("Before initialization stuff");
    return new ClassB();
}

Ответ 2

Еще один взлом, если вам удастся вызвать статический метод.

public class ClassA
{
    public ClassA()
    {
        Debug.WriteLine("Call A Constructor");
    }
}

public class ClassB:ClassA
{
    public ClassB():this(aMethod())
    {
    }

    private ClassB(object empty):base()
    {
        Debug.WriteLine("Class B Second Constructor");
    }

    private static object aMethod()
    {
        Debug.WriteLine("Run me First");
        return null;
    }
}

Ответ 3

Другим элегантным решением было бы полностью переосмыслить, как ваши объекты будут построены. В конструкторе вашего базового класса вы можете вызвать свою собственную функцию construct и опустить зависимые будущие конструкторы следующим образом:

public class ClassA
{
    public ClassA()
    {
        Construct();
    }

    public virtual void Construct()
    {
        Console.WriteLine("3");
    }
}

public class ClassB : ClassA
{
    public override void Construct()
    {
        Console.WriteLine("2");
        base.Construct();
    }
}

public class ClassC : ClassB
{
    public override void Construct()
    {
        Console.WriteLine("1");
        base.Construct();
    }
}

Ответ 4

Вы не можете сделать это с помощью С#. Лучше всего извлечь этот код в свой собственный метод в родительском, а затем вызвать его из ребенка, когда вы будете готовы.

Ответ 5

С# не позволяет вызывать базовые конструкторы внутри тела конструктора, отличные от Java.

Ответ 6

Вы не можете вызвать базовый конструктор. Но другое дело в том, что при объявлении объекта производного класса вызывается как производный конструктор, так и база.

    class ClassA
{
    public ClassA()
    {
        Console.WriteLine("Initialization");
    }  
}

class ClassB : ClassA
{
    public ClassB() //: base() 
    {
        // Using :base() as commented above, I would execute ClassA ctor before                                                         //          Console.WriteLine as it is below this line... 
        Console.WriteLine("Before new");
        //base() //Calls ClassA constructor using inheritance
        //Run some more Codes here...
    }
}
void main(string[] args)
    {
      ClassB b = new ClassB();

    }

Ответ 7

Недавно я столкнулся с сценарием, где мне нужно было вычислить некоторую логику, прежде чем передавать результат в базу.

Я мог бы просто сделать что-то вроде

public SomeConstructor: base(FlagValue == FlagValues.One || FlagValues.Two ? "OptionA" : "OptionB")
{

}

Но я нахожу это уродливым и могу быть очень длинным по горизонтали. Поэтому я решил использовать методы Func Anonymous.

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

public class SomeBaseClass
{
  public SomeBaseClass(Func<string> GetSqlQueryText){
    string sqlQueryText = GetSqlQueryText();
    //Initialize(sqlQueryText);
  }
}

Теперь вы наследуете это и хотите сделать некоторую логику для определения текста запроса sql,

public class SomeSqlObject : SomeBaseClass
{
  public SomeSqlObject(ArchiveTypeValues archiveType)
        : base(delegate()
        {
            switch (archiveType)
            {
                case ArchiveTypeValues.CurrentIssues:
                case ArchiveTypeValues.Archived:
                    return Queries.ProductQueries.ProductQueryActive;
                case ArchiveTypeValues.AllIssues:
                    return     string.Format(Queries.ProductQueries.ProductQueryActiveOther, (int)archiveType);
                default:
                    throw new InvalidOperationException("Unknown archiveType");
            };
        })
    {
        //Derived Constructor code here!
    }

}

Таким образом, вы можете выполнить код до вызова Base и (на мой взгляд) это не очень хаки.

Ответ 8

У меня была та же проблема. Я нашел это решение лучшим, если у вас нет доступа к базовому классу.

public class BaseClass
{
    public BaseClass(string someValue)
    {
        Console.WriteLine(someValue);
    }
}

public class MyClass : BaseClass
{
    private MyClass(string someValue)
        : base(someValue)
    {
    }

    public static MyClass GetNewInstance(string someValue, bool overrideValue = false)
    {
        if (overrideValue)
        {
            someValue = "42";
        }
        return new MyClass(someValue);
    }
}