System.Typeのデフォルトコンストラクター(つまり、パラメーターなしのインスタンスコンストラクター)を取得する最も効率的な方法は何ですか?
私は以下のコードの行に沿って何かを考えていましたが、それを行うためのより簡単で効率的な方法があるはずです。
Type type = typeof(FooBar)
BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
type.GetConstructors(flags)
.Where(constructor => constructor.GetParameters().Length == 0)
.First();
type.GetConstructor(Type.EmptyTypes)
ConstructorInfoオブジェクトを実際にneedする場合は、 Curt Hagenlocherの答え を参照してください。
一方、System.Type
から実行時にオブジェクトを作成しようとしているだけの場合は、 System.Activator.CreateInstance
を参照してください。アクティベーターはConstructorInfo.Invoke
)よりも多くの詳細を処理しますが、muchの見た目も劣ります。
ジェネリック型パラメーターがある場合、Jeff Bridgmanの答えが最適です。構築したい型を表すTypeオブジェクトしかない場合、Alex Lymanが示唆したようにActivator.CreateInstance(Type)
を使用できますが、遅いと言われています(個人的にプロファイルしていません)。
ただし、これらのオブジェクトを非常に頻繁に構築している場合は、動的にコンパイルされたLinq式を使用したより雄弁なアプローチがあります。
using System;
using System.Linq.Expressions;
public static class TypeHelper
{
public static Func<object> CreateDefaultConstructor(Type type)
{
NewExpression newExp = Expression.New(type);
// Create a new lambda expression with the NewExpression as the body.
var lambda = Expression.Lambda<Func<object>>(newExp);
// Compile our new lambda expression.
return lambda.Compile();
}
}
返されたデリゲートを呼び出すだけです。 Linq式を絶えず再コンパイルするとコストがかかる可能性があるため、このデリゲートをキャッシュする必要がありますが、デリゲートをキャッシュして毎回再利用すると、非常に高速になります。個人的には、タイプごとにインデックスが付けられた静的なルックアップ辞書を使用しています。この関数は、Type情報しかわからないシリアル化されたオブジェクトを扱うときに役立ちます。
注:タイプが構築可能でない場合、またはデフォルトのコンストラクターがない場合、これは失敗する可能性があります!
クラスをインスタンス化するデフォルトのコンストラクターのみを取得し、関数のジェネリック型パラメーターとして型を取得する場合は、次の操作を実行できます。
T NewItUp<T>() where T : new()
{
return new T();
}