コンストラクターを直接呼び出して、デリゲートを構築するためのジェネリック メソッド。指定されたデリゲート タイプのシグネチャを持つ指定されたタイプのコンストラクターを自動的に検索し、そのタイプのデリゲートを構築します。ここにコード:
/// <summary>
/// Reflective object construction helper.
/// All methods are thread safe.
/// </summary>
public static class Constructor
{
/// <summary>
/// Searches an instanceType constructor with delegateType-matching signature and constructs delegate of delegateType creating new instance of instanceType.
/// Instance is casted to delegateTypes's return type.
/// Delegate's return type must be assignable from instanceType.
/// </summary>
/// <param name="delegateType">Type of delegate, with constructor-corresponding signature to be constructed.</param>
/// <param name="instanceType">Type of instance to be constructed.</param>
/// <returns>Delegate of delegateType wich constructs instance of instanceType by calling corresponding instanceType constructor.</returns>
public static Delegate Compile(Type delegateType,Type instanceType)
{
if (!typeof(Delegate).IsAssignableFrom(delegateType))
{
throw new ArgumentException(String.Format("{0} is not a Delegate type.",delegateType.FullName),"delegateType");
}
var invoke = delegateType.GetMethod("Invoke");
var parameterTypes = invoke.GetParameters().Select(pi => pi.ParameterType).ToArray();
var resultType = invoke.ReturnType;
if(!resultType.IsAssignableFrom(instanceType))
{
throw new ArgumentException(String.Format("Delegate's return type ({0}) is not assignable from {1}.",resultType.FullName,instanceType.FullName));
}
var ctor = instanceType.GetConstructor(
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, parameterTypes, null);
if(ctor == null)
{
throw new ArgumentException("Can't find constructor with delegate's signature","instanceType");
}
var parapeters = parameterTypes.Select(Expression.Parameter).ToArray();
var newExpression = Expression.Lambda(delegateType,
Expression.Convert(Expression.New(ctor, parapeters), resultType),
parapeters);
var @delegate = newExpression.Compile();
return @delegate;
}
public static TDelegate Compile<TDelegate>(Type instanceType)
{
return (TDelegate) (object) Compile(typeof (TDelegate), instanceType);
}
}
Yappiプロジェクトのソースの一部です。これを使用すると、パラメーターを持つコンストラクターを含む、指定された型の任意のコンストラクターを呼び出すデリゲートを構築できます (ref および out パラメーターを除く)。
使用例:
var newList = Constructor.Compile<Func<int, IList<String>>>(typeof (List<String>));
var list = newList(100);
デリゲートの構築後、静的辞書のどこかに、またはジェネリックパラメーターを持つクラスの静的フィールドに保存します。毎回新しいデリゲートを構築しないでください。特定の型の複数のインスタンスを構築するために 1 つのデリゲートを使用します。