База конструктора вызовов после выполнения кода
Скажем, у нас есть класс 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()
; Но я не могу сделать это на С#. Есть ли другой синтаксис или другой способ сделать это?
Ответы
Ответ 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);
}
}