15

仕事中に既存のコードを読んで、私はこれがどのようにうまくいくことができるか疑問に思いました。アセンブリ内にクラスを定義しています。

[Serializable]
public class A
{
    private readonly string _name;
    private A(string name)
    {
        _name = name;
    }
}

そして別のアセンブリでは:

public void f(Type t) {
    object o = Activator.CreateInstance(t);
}

そしてその単純な呼び出しf(typeof(A))

AFAIKでは、ctorが宣言されている場合、コンパイラはデフォルトのpublicパラメータなしコンストラクタを生成することを想定していないため、パラメータなしのコンストラクタがないことについての例外が予想されました。

このコードは.NET 2.0で動作します。

[編集]すみませんが、私は実際のコードを読み違えています...私が提供したサンプルはそれを例示していません。 JonHの回答を受け入れたのは、それが良い情報を提供してくれたからです。


  • @Codesleuth - しばらくしてから、これらすべてのルールを覚えていると、片頭痛が発生することがあります。答えは下記をご覧ください。 - JonH

4 답변


9

これを見なさい:リフレクションを使用してC#でデフォルトコンストラクタなしでtypeのインスタンスを作成する

これは未来へもあります、これはC#4.0に関してです:

Microsoftが2010年1月4日に投稿した   14:08

あなたのバグを確認しました   その行動が   あなたが説明したのは仕様によるものです。私たちは今   この問題をアーカイブしています。ご利用いただきありがとうございます   Visual Studioと.NET Framework!

Activator.CreateInstanceには多くのオーバーロードがあります。     単一の型パラメータのみを取ります     デフォルトのパラメータなしを呼び出す     コンストラクタ。を取るコンストラクタ     のようなオプションのパラメータ     あなたの例はデフォルトではありません     コンストラクタそれらを呼び出すにはあなたが必要です     に:

  1. 引数配列をとるオーバーロードを使う
  2. Type.Missingを引数として渡します
  3. BindingFlagsにOptionalParamBindingを指定する

これが一例です。

Activator.CreateInstance(typeof(MyClassName),
 BindingFlags.CreateInstance |
 BindingFlags.Public |
 BindingFlags.Instance |
 BindingFlags.OptionalParamBinding,
 null, new Object[] {Type.Missing}, null);

ありがとう、

ウェイタオ蘇

マイクロソフト株式会社


  • だから多分Sebはクラスを定義しましたA他の場所、またはロード元のアセンブリが更新されていません。それはコードの異常というよりはむしろプロジェクト/ソリューションの問題のように思えます。 - Codesleuth
  • @Codesleuth - おそらく。 - JonH

22

代替案は:

object obj = System.Runtime.Serialization.FormatterServices
          .GetUninitializedObject(t);

これはメモリ内にオブジェクトを作成しますがしない任意のコンストラクタを実行します。怖い。


  • それです非常に怖い、そしてまさに私が必要としていたもの! +1 - ashes999
  • 通常@ashesはシリアライザ、プロキシ(RPC)、またはオームによってのみ使用されます。 - Marc Gravell
  • それは私の簡単なテストdllタイプvarに働きました。しかし、いくつかのクラス、メソッドなどを含むより複雑なdllでは、あなたの行はクラッシュしました。 System.MemberAccessException'タイプの未処理の例外追加情報:抽象クラスを作成できません。 - humudu
  • @humuduええ、コンストラクタを迂回しても抽象型を作成することはできません。これはランタイムではサポートされていません。抽象インスタンスを作成できたとしても、何かが非常に壊れています。 - Marc Gravell
  • 最初にロードしたメソッドとは別のメソッドでランタイム決定のdllメソッドにアクセスして実行したいのですが。後でアクセスできるように、ここでオブジェクトプロパティに変換しようとしましたが、万が一提案がありますか。 - humudu

0

これはあなたにとっては現実的ではないかもしれませんが、最も簡単なことは引数リストを型のように渡すことです。

Activator.CreateInstance(t、 "name");

あなたはf()が実際に何をしようとしているのかを考えたいでしょう。それはA型のオブジェクトをインスタンス化すべきでしょうか。他にどのようなクラスがインスタンス化されますか?

1つの可能性は、クラスAのCreateInstance()に正しいパラメーターを渡すswitchステートメントをf()内に含めることです。これは拡張できませんが、それは問題にならない可能性があります。


0

の混乱を招く2つの味がありますCreateInstance:を取るものタイプのSystem.Typeとしてパラメータ、別の型パラメータ T

最初の1つ:

object Activator.CreateInstance(type As Type) { }

二つ目:

T Activator.CreateInstance<T>() { }

二番目1つは、パブリックのパラメータのないコンストラクタがないとクラスには機能しないものです。

2番目のものを使用しても意味がありません。それが使用されるどんな場合でも、それは持っている方が良いでしょうwhere T : new()あなたのクラスに制約を与え、単純にTのコンストラクタ

MSDNのドキュメント同意する:

一般的には、CreateInstanceアプリケーションコードでは、   型はで知っている必要があるため   コンパイル時間型がわかっている場合   コンパイル時、通常のインスタンス化   構文を使用することができます(new演算子in   C#、NewVisual Basicでは、gcnewに   C ++)

編集:話しすぎたのかもしれません。最初のバージョンも動作するはずがないようです。


  • ええ、最初のバージョンでも同じエラーが発生します。このオブジェクトにはパラメータなしのコンストラクタが定義されていません。 - Evan

リンクされた質問


関連する質問

最近の質問