23

假设我们有 A 类和 B 类。B 类扩展 A 类。(B 类:A 类)

现在假设每当我实例化 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()after来做到这一点Console.WriteLine()。但我不能在 C# 中实现它。有没有其他语法或其他方法可以做到这一点?

4

10 回答 10

32

There's a hacky way of doing it using an instance variable initializer:

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();
    }    
}

The less hacky way of doing it is to rethink how you construct a ClassB to start with. Instead of having clients call the constructor directly, provide a static method for them to call:

public static ClassB CreateInstance()
{
    Console.WriteLine("Before initialization stuff");
    return new ClassB();
}
于 2012-05-26T06:21:18.513 回答
8

如果您可以避免调用静态方法,则另一种技巧。

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;
    }
}
于 2013-03-14T21:38:24.953 回答
6

实际上,您可以:

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

但如果可能的话,我宁愿不使用这个技巧。

于 2018-07-19T20:27:04.093 回答
5

另一个优雅的解决方案是完全重新考虑你的对象是如何构造的。在基类的构造函数中,您可以调用自己的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();
    }
}
于 2015-10-06T11:35:32.063 回答
1

你不能用 C# 做到这一点。你最好的办法是将该代码提取到它自己的父方法中,然后在你准备好时从孩子那里调用它。

于 2012-05-26T05:50:05.003 回答
1

我很惊讶没有人建议使用抽象方法 - 尽管它确实依赖于被实现为抽象类的基础,这不适用于所有情况(尽管你可以简单地分叉继承并将非抽象堆叠在顶部,如果你必须)。这样做的好处是可以确保代码的完整性,而无需求助于黑客行为。因为我们使用的是抽象,所以不声明 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()
    {
    }
}
于 2021-11-08T04:50:33.987 回答
0

C# 不允许在构造函数体内调用基本构造函数,这与 Java 不同。

于 2012-05-26T05:49:20.603 回答
0

您不能调用基本构造函数。但不同的是,当您声明派生类的对象时,会调用派生的构造函数和基类。

    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();

    }
于 2012-05-26T05:59:21.420 回答
0

最近我遇到了一个场景,我需要在将结果传递到 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 之前执行代码,并且(在我看来)它并不是真正的 hacky。

于 2014-04-14T20:41:07.530 回答
0

我有同样的问题。如果您无权访问基类,我发现此解决方案是最好的。

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);
    }
}
于 2017-07-18T11:40:18.337 回答