代码执行后调用构造函数基
本文关键字:构造函数 调用 执行 代码 | 更新日期: 2023-09-27 18:35:33
假设我们有A类和B类。
现在假设每当我实例化 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...
}
}
在我通常使用的编程语言中,我可以通过在Console.WriteLine()
之后简单地调用super()
来做到这一点;但是我不能用 C# 做到这一点。还有其他语法或其他方法可以做到这一点吗?
有一种使用实例变量初始值设定项的黑客方法:
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();
}
如果你能侥幸调用静态方法,这是另一个技巧。
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;
}
}
实际上,您可以:
class Foo
{
public Foo(string s)
{
Console.WriteLine("inside foo");
Console.WriteLine("foo" + s);
}
}
class Bar : Foo
{
public Bar(string s) : base(((Func<string>)(delegate ()
{
Console.WriteLine("before foo");
return "bar" + s;
}))())
{
Console.WriteLine("inside bar");
}
}
class Program
{
static void Main(string[] args)
{
new Bar("baz");
}
}
输出:
before foo
inside foo
foobarbaz
inside bar
但如果可能的话,我宁愿不使用这个技巧。
另一个优雅的解决方案是完全重新思考对象的构造方式。在基类的构造函数中,可以调用自己的 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();
}
}
C# 不允许在构造函数体内调用基构造函数,这与 Java 不同。
你不能用 C# 做到这一点。最好的办法是将该代码提取到父级中它自己的方法中,然后在准备就绪时从子级调用它。
惊讶没有人建议使用抽象方法 - 尽管它确实依赖于将基础实现为抽象类,这并不适用于所有情况(尽管您可以简单地分叉继承并将非抽象堆叠在顶部如果 yu 必须的话)。这样做的好处是可以确保代码的完整性,而无需诉诸黑客攻击。因为我们使用的是抽象,所以不可能在不声明 initCode 的情况下实例化派生类。
using System;
abstract class ClassA
{
internal abstract initCode();
public ClassA()
{
initCode();
Console.WriteLine("Initialization");
}
}
class ClassB : ClassA
{
public ClassB()
{
}
internal override initCode()
{
Console.WriteLine("Before new");
return 0; // We really don't care
}
}
//If you need to effectively get the non-abstract of ClassA
class ClassC : ClassA
{
public ClassB()
{
}
internal override initCode()
{
}
}
不能调用基构造函数。但另一件事是,当您声明派生类的对象时,会调用构造函数派生和基。
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();
}
最近我遇到了一个场景,我需要在将结果传递到 base 之前计算一些逻辑。
我可以做这样的事情
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 之前执行代码,并且(在我看来)它并不是真正的黑客。
我遇到了同样的问题。如果您无法访问基类,我发现此解决方案是最好的。
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);
}
}