82

例として次のクラスを取ります。

class Sometype
{
    int someValue;

    public Sometype(int someValue)
    {
        this.someValue = someValue;
    }
}

次に、リフレクションを使ってこのタイプのインスタンスを作成します。

Type t = typeof(Sometype);
object o = Activator.CreateInstance(t);

通常これはうまくいきますが、SomeTypeパラメータのないコンストラクタを定義していません。Activator.CreateInstance型の例外をスローしますMissingMethodExceptionメッセージ付き」このオブジェクトにはパラメータなしのコンストラクタが定義されていません。「このタイプのインスタンスを作成する別の方法はありますか?すべてのクラスにパラメータのないコンストラクタを追加するのはちょっと面倒です。


  • FormatterServices.GetUninitializedObject未初期化文字列を作成することはできません。あなたは例外が発生する可能性があります。System.ArgumentException: Uninitialized Strings cannot be created.これを覚えておいてください。 - Bartosz Pierzchlewicz
  • 頭を上げてくれてありがとう、でも私はすでに文字列と基本型を別々に扱っています。 - Aistina

4 답변


122

私はもともとこの答えを投稿しましたここにしかし、これはまったく同じ質問ではありませんが、同じ答えを持っているので、ここに転載します。

FormatterServices.GetUninitializedObject()コンストラクタを呼び出さずにインスタンスを作成します。を使ってこのクラスを見つけましたリフレクターそしてコアの.NETシリアライゼーションクラスのいくつかを掘り下げる。

以下のサンプルコードを使用してテストしましたが、うまく機能しているように見えます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Runtime.Serialization;

namespace NoConstructorThingy
{
    class Program
    {
        static void Main(string[] args)
        {
            MyClass myClass = (MyClass)FormatterServices.GetUninitializedObject(typeof(MyClass)); //does not call ctor
            myClass.One = 1;
            Console.WriteLine(myClass.One); //write "1"
            Console.ReadKey();
        }
    }

    public class MyClass
    {
        public MyClass()
        {
            Console.WriteLine("MyClass ctor called.");
        }

        public int One
        {
            get;
            set;
        }
    }
}



71

このCreateInstanceメソッドのオーバーロードを使用します。

public static Object CreateInstance(
    Type type,
    params Object[] args
)

指定されたのインスタンスを作成します   最良のコンストラクタを使ってタイプする   指定されたパラメーターと一致します。

見る:http://msdn.microsoft.com/en-us/library/wcxyzt4d.aspx


  • この解決法は問題を単純化し過ぎる。自分のタイプがわからず、「このType変数にTypeのオブジェクトを作成するだけ」と言った場合はどうなりますか。 - kamii

18

ときにベンチマークのパフォーマンス(T)FormatterServices.GetUninitializedObject(typeof(T))遅くなりました。同時にコンパイルされた式は、デフォルトのコンストラクタを持つ型に対してのみ機能しますが、速度が大幅に向上します。私はハイブリッドアプローチを取りました:

public static class New<T>
{
    public static readonly Func<T> Instance = Creator();

    static Func<T> Creator()
    {
        Type t = typeof(T);
        if (t == typeof(string))
            return Expression.Lambda<Func<T>>(Expression.Constant(string.Empty)).Compile();

        if (t.HasDefaultConstructor())
            return Expression.Lambda<Func<T>>(Expression.New(t)).Compile();

        return () => (T)FormatterServices.GetUninitializedObject(t);
    }
}

public static bool HasDefaultConstructor(this Type t)
{
    return t.IsValueType || t.GetConstructor(Type.EmptyTypes) != null;
}

つまり、create式は事実上キャッシュされ、型が最初にロードされたときにのみペナルティが発生します。値型も効率的な方法で扱います。

あれを呼べ:

MyType me = New<MyType>.Instance();

ご了承ください(T)FormatterServices.GetUninitializedObject(t)stringでは失敗します。したがって、空の文字列を返すために、stringに対する特別な処理が行われます。


  • 誰かのコードの1行を見るだけで1日を節約できるのは不思議です。ありがとうございます!パフォーマンス上の理由から、投稿に導いたトリックは完了です。)FormatterServicesクラスとActivatorクラスは、コンパイルされた式と比較してパフォーマンスが低下しています。 - jmodrak
  • @nawfalあなたの文字列の特別な扱いに関して、私はそれがこの特別な扱いなしでは文字列に対して失敗することを知っています、しかし私はただ知りたいのです。すべて他の種類は? - Sнаđошƒаӽ
  • @Sнаđошƒаӽ残念ながらありません。与えられた例は必要最低限のもので、.NETにはさまざまなタイプのタイプがあります。例えばあなたがデリゲート型を渡す場合、どのようにあなたはあなたにそれをインスタンスにするのでしょうか?それとも、コンストラクタがあなたがそれについて何ができるかを投げたら?それを処理するためのさまざまな方法があります。私は私の図書館でもっとたくさんのシナリオを扱うためにこれに答えて答えた。今のところどこにも掲載されていません。 - nawfal

4

良い答えだがドットネットのコンパクトフレームワークでは使えない。これはCF.Net上で動作するソリューションです...

class Test
{
    int _myInt;

    public Test(int myInt)
    {
        _myInt = myInt;
    }

    public override string ToString()
    {
        return "My int = " + _myInt.ToString();
    }
}

class Program
{
    static void Main(string[] args)
    {
        var ctor = typeof(Test).GetConstructor(new Type[] { typeof(int) });
        var obj = ctor.Invoke(new object[] { 10 });
        Console.WriteLine(obj);
    }
}


  • これが、デフォルト以外のコンストラクタを呼び出す方法です。まったくコンストラクタを呼び出さずにオブジェクトを作成したいとは思わない。 - Rory MacLeod
  • カスタムシリアライザを作成している場合は、コンストラクタを呼び出さずにオブジェクトを作成できます。 - Autodidact
  • うん、それがこの質問のための正確なユースケースシナリオだ:) - Aistina
  • @Aistinaたぶんあなたは質問にこの情報を追加することができますか?ほとんどの人は彼らのctorsを呼ばずにオブジェクトを作成することに反対し、それについてあなたと議論するのに時間がかかりますが、あなたのユースケースは実際にそれを正当化するので、私はそれが質問自体に非常に関連していると思います。 - julealgon

リンクされた質問


関連する質問

最近の質問