web-dev-qa-db-ja.com

抽象C#クラスで抽象コンストラクターを作成できないのはなぜですか?

抽象クラスを作成しています。派生クラスのそれぞれに、コンストラクターの特定の署名を強制的に実装させたいです。そのため、メソッドを強制的に実装させたいと思ったら、私がしたであろうことを行い、抽象メソッドを作成しました。

public abstract class A
{
    abstract A(int a, int b);
}

ただし、このアイテムでは抽象修飾子が無効であるというメッセージが表示されます。私の目標は、このようなコードを強制することでした。

public class B : A
{
    public B(int a, int b) : base(a, b)
    {
        //Some other awesome code.
    }
}

これはすべてC#.NETコードです。誰も私を助けることができますか?

更新1

いくつか追加したかったのです。私が最後にしたのはこれでした。

private A() { }

protected A(int a, int b)
{
    //Code
}

これは、一部の人々が言っ​​ていることです。デフォルトはプライベートであり、クラスはコンストラクターを実装する必要があります。ただし、シグネチャA(int a、int b)を持つコンストラクターは強制されません。

public abstract class A
{
    protected abstract A(int a, int b)
    {


    }
}

更新2

これを回避するために、デフォルトのコンストラクタをプライベートにし、他のコンストラクタを保護しました。コードを機能させる方法を探しているわけではありません。私はそれを大事にしました。 C#でこれができない理由を理解したいと思っています。

58
Anthony D

抽象は、抽象ではない子クラスでオーバーライドする必要があることを意味し、コンストラクタをオーバーライドできないため、抽象コンストラクタを持つことはできません。

考えてみると、これは理にかなっています。なぜなら、常に子クラスのコンストラクタを(new演算子を使用して)呼び出し、ベースクラスは呼び出さないからです。

一般的に、C#で特定のコンストラクターシグネチャを適用する唯一の方法は、new()ジェネリック制約を使用することです。これにより、型パラメーターにパラメーターなしのコンストラクターが存在します。

51
Tamas Czinege

クラスAのコンストラクタを

protected A(int a, int b)
{
    // Some initialisation code here
}

デフォルトのコンストラクターがないため、サブクラスで使用する必要があります。

ただし、コンストラクタの実際の署名は変更できます。私の知る限り、サブクラスがコンストラクターに特定の署名を使用するよう強制する方法はありません。コンストラクタは抽象化できないと確信しています。

これは何のために正確に必要ですか?これに対する回避策を提案できるかもしれません。

26
Jamie Penney

コンストラクターをオーバーライドすることはできないため、抽象コンストラクターを定義することはできませんが、抽象ファクトリーメソッドを抽象基本クラスに配置できます。すべての派生クラスはそれをオーバーライドする必要があります。

public abstract class A 
{ 
    abstract A MakeAInstance(int a, int b); 
} 

public class B : A 
{ 
    // Must implement:
    override A MakeAInstance(int a, int b) {
        // Awesome way to create a B instance goes here
    }
} 
7
John Saunders

複数の理由:

1)コンストラクターは継承されないため、オーバーライドできません。

2)コンストラクターは、特定のインスタンスを呼び出す必要がないため、静的メンバー関数です。抽象は、「仮想」を意味します。これは、特定のインスタンスがどのようにサブクラス化されるかによって実装が変化する可能性があることを意味します。

5
Mats

各派生クラスは独自のコンストラクターを定義する必要があり、必要なパラメーターを取得できるため、コンストラクター署名を適用することはできません。

特定の変数セットを派生クラスのオブジェクトに渡す必要がある場合は、派生クラスで実装する必要がある抽象メソッドを定義します。クラスが抽象メソッドを実装しない場合、コンパイラエラーが発生します。

4
devio

私が引数をとるctorで「通常の」パブリッククラスを作成しようとしていたので、これが誰かnewbに役立つことを願っています。

私はこれを以前は知りませんでした:保護されたctorを作成すると、子クラスはそれを見るが、プログラムの残りはそれを見てはいけないcs ...)

1
bresleveloper

すべてのサブクラスは、スーパークラスのコンストラクターを呼び出す限り、常に独自のコンストラクターを指定できます。そのため、クラスに特定のコンストラクターを強制する方法はありません(少なくとも、Javaで動作する方法です)。ファクトリパターンを使用すると、どこかで取得できることがわかります-インターフェイスでファクトリメソッドを定義できます-しかし、抽象ベースクラスは必要なオブジェクトの実際のクラスを知らないため、別のファクトリクラスが必要になります作成した。

ただし、あなたが抱えている問題のより具体的な例を追加すると、他の/より良い応答を促すことができます。いくつかの一般的なインスタンス化コードを探していますか、または抽象基本クラスの特定の設定を行う必要があることを懸念していますか?

抽象クラスで実行する必要がある初期化について懸念がある場合は、そのためのメソッドを作成し、そのメソッドの使用法を文書化します。

0

これが役立つかどうかはわかりませんが、これはあなたの問題の解決策だと思います:

public class A
{
  public A(int a, int b)
  {
    DoSomething(int a, int b);
  }

  virtual public void DoSomething(int a, int b)
  {

  }
}

public class B : A
{
  override public void DoSomething(int a, int b)
  {
    //class specific stuff
  }
}

その結果、派生クラスで必要な引数を指定したコンストラクターを正しい動作で呼び出すことができます。

0
mo.