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()後に呼び出すだけでそれを行うことができます。Console.WriteLine()しかし、C#では作成できません。それを行うための他の構文または他の方法はありますか?

4

10 に答える 10

32

インスタンス変数初期化子を使用してそれを行うためのハッキーな方法があります:

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

もう1つの洗練された解決策は、オブジェクトの構成方法を完全に再考することです。基本クラスの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

基本コンストラクターを呼び出すことはできません。しかし、別のことは、派生クラスのオブジェクトを宣言すると、コンストラクター派生とベースの両方が呼び出されることです。

    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

C#では、Javaとは異なり、コンストラクター本体内でベースコンストラクターを呼び出すことはできません。

于 2012-05-26T05:49:20.603 に答える
0

最近、結果をベースに渡す前にロジックを計算する必要があるシナリオに遭遇しました。

私はただのようなことをすることができました

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

}

しかし、それは醜く、水平方向に非常に長くなる可能性があることがわかりました。そこで、代わりにFuncAnonymousメソッドを使用することにしました。

たとえば、基本クラスがあると想像してください。

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が呼び出される前にコードを実行でき、(私の意見では)実際にはハッキーではありません。

于 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 に答える