web-dev-qa-db-ja.com

C#でクラス外からプライベートコンストラクターにアクセスする

プライベートデフォルトコンストラクターとパラメーターを持つパブリックコンストラクターを使用してクラスを定義する場合、プライベートコンストラクターにアクセスするにはどうすればよいですか?

public class Bob
{
   public String Surname { get; set; }

   private Bob()
   { }

   public Bob(string surname)
   {
      Surname = surname;
   }
}

次のように、クラスの静的メソッドを介してプライベートコンストラクターにアクセスできます。

public static Bob GetBob()
{
   return new Bob();
}

(私の理解によれば)拡張メソッドはのように変換されるので、拡張メソッドを介してプライベートコンストラクターにアクセスできると思いました。クラスの静的メソッドですが、できません:

static class Fred
{
   public static Bob Bobby(this Bob bob)
   {
      return new Bob();
   }
}

では、どうすればプライベートコンストラクターにアクセスできますか?

ありがとうございました


編集:

これを実行したかった理由は、ビジネスクラスの1つに対してテストを作成したかったのですが、このクラスのコンシューマーがオブジェクトを誤ってインスタンス化できないようにするためです。私はそれをテストしているので、どのような状況でテストが失敗するかを知っています(私は願っています!)。私はまだn00bをテストしているので、私の考えは物事を行う「間違った方法」であったかもしれないし、そうでなかったかもしれません。

テスト戦略を変更して、このクラスのコンシューマーと同じように処理を実行します。つまり、パブリックメソッドを呼び出し、パブリックメソッドがOKかどうか、プライベートメソッドがOKであると想定します。私はまだプライベートメソッドをテストしたいのですが、上司成果物で首から息を吸っています:-(

26
AndrewJacksonZA

新しい答え(9年後)

Activator.CreateInstance には、非パブリックコンストラクターを使用できるようにするいくつかのオーバーロードがあります。

Activator.CreateInstance(typeof(YourClass), true);

true =非公開コンストラクターを使用します。

古い答え

デフォルトのコンストラクターは、理由によりプライベートです。開発者はそれを楽しみのために非公開にしません。

ただし、デフォルトのコンストラクターを引き続き使用する場合は、リフレクションを使用して取得します。

var constructor = typeof(Bob).GetConstructor(BindingFlags.NonPublic|BindingFlags.Instance, null, new Type[0], null);
var instance = (Bob)constructor.Invoke(null);

編集

テストについてのあなたのコメントを見ました。保護されたメソッド/プロパティをテストしないでください。パブリックAPIを介してこれらのメソッド/プロパティをテストできない場合は、おそらく何か問題があります。それらを削除するか、クラスをリファクタリングします。

編集2

バインディングフラグを忘れました。

44
jgauffin

この問題を回避するには、いくつかの方法があります。

One:コンストラクターをパブリックにします。クラスの外部からアクセスする必要がある場合、なぜそれがプライベートなのですか(テストのためにプライベートコンストラクターにのみアクセスしたい場合があります。その場合、これは有効な問題です)。

Two:コンストラクターを保護し、派生クラスを介してアクセスします。

public class Bob
{
    public String Surname { get; set; }

    protected Bob()
    { }

    public Bob(string surname)
    {
        Surname = surname;
    }
}

public class Fred : Bob
{
    public Fred()
        : base()
    {
    }
}

Three:リフレクションを使用します(jgauffinで示されているように)。

2
Dr Herbie

リフレクションを介してプライベートコンストラクターを呼び出す方法を説明する@jgauffinの回答に加えて:

プライベートコンストラクターの修飾子を変更することは可能ですか?

コードにファクトリパターンを実装しているようです。したがって、修飾子はinternalであると想定されます。

_public class Product
{
   //others can't create instances directly outside the Assembly
   internal Product() { }    
}
public class ProductProvider
{
   //they can only get standardized products by the provider
   //while you have full control to Product class inside ProductProvider
   public static Product CreateProduct()
   {
       Product p = new Product();    
       //standardize the product
       return p;
   }  
}
_

拡張メソッド

_public static MyExt
{
   public static void DoSomething(this Product p) { }
}
_

p.DoSomething()の呼び出しは、実際にはMyExt.DoSomething(p)と同じです。このメソッドをProductクラスに入れていません。

2
Cheng Chen

Dotnet coreを使用している場合は、リフレクションをいじることなく、次のことを実行できます。

YourCustomObject player = (YourCustomObject)Activator.CreateInstance(typeof(YourCustomObject),true);

アクティベーターはシステム名前空間にあります。

1
DenLilleMand

クラスにプライベートコンストラクターのみがあり、パブリックコンストラクターがない場合、このクラス内のネストされたクラスからのみアクセスできます。考慮に値するのは、プライベートデフォルトコンストラクターを持つクラスを派生できないという事実です。したがって、クラスのインスタンスがこのクラス内のネストされたクラス内でのみ作成されることを目的としている場合にのみ、コンストラクターをプライベートとして宣言することは意味があります(パブリックインストラクターがないクラス内)。このクラスをインスタンス化するための有効な場所は他にありません。

0
Anas Al Kala