特定のインターフェイスを実装する型をインスタンス化するオブジェクトファクトリを作成しようとしていますが、インスタンス化する型が実行時に不明で、反射。私はいくつかの例を見つけましたが、これは表現を使用して可能かもしれませんが、私の場合に適した例を見つけることはできませんでした。単にそれが可能ではないかもしれないかもしれないかもしれないが、私は確かめるためにここに質問を投げたかった。C#式をリフレクションなしで動的にインスタンス化する式
は、だから私が持っているもの、これはここまでです:
public static Func<Type, object[], IMyInterface> FactoryExpression =
Expression.Lambda<Func<Type, object[], IMyInterface>>(
/* Something that creates an instance of the type with given arguments */
).Compile()
public static IMyInterface GetTypeOfMyInterface()
{
Type t = Type.GetType(GetTypeNameFromSomewhere());
ConstructorInfo c = t.GetConstructors().First();
object[] args = ResolveCostructorArguments(c.GetParameters());
return FactoryExpression(t, args);
}
私は式のこれらのタイプの少しのexprienceを持っています。これをすべて動作させることは可能なのでしょうか、あるいは私は反射に落ちなければなりませんか?
EDIT:ジョン・ハンナの例を使用することにより
私は、次のを思い付いた:
public class TypeInitializer<TResult>
{
private static readonly ConcurrentDictionary<string, Func<object[], TResult>> InstanceCreationMethods =
new ConcurrentDictionary<string, Func<object[], TResult>>();
public static TResult CreateInstance(ConstructorInfo constructorInfo, params object[] arguments)
{
ParameterInfo[] parameterInfo = constructorInfo.GetParameters();
IEnumerable<Type> parameterTypes = parameterInfo.Select(p => p.ParameterType);
string constructorSignatureKey = GetConstructorSignatureKey(constructorInfo.DeclaringType, parameterTypes);
Func<object[], TResult> factoryMethod = InstanceCreationMethods.GetOrAdd(constructorSignatureKey, key =>
{
Expression[] args = new Expression[parameterInfo.Length];
ParameterExpression param = Expression.Parameter(typeof(object[]));
for (int i = 0; i < parameterInfo.Length; i++)
args[i] = Expression.Convert(Expression.ArrayIndex(param, Expression.Constant(i)), parameterInfo[i].ParameterType);
return Expression
.Lambda<Func<object[], TResult>>(Expression.Convert(Expression.New(constructorInfo, args), typeof(TResult)), param)
.Compile();
});
return factoryMethod(arguments);
}
private static string GetConstructorSignatureKey(Type type, IEnumerable<Type> argumentTypes) => string.Concat(type.FullName, " (", string.Join(", ", argumentTypes.Select(at => at.FullName)), ")");
}
意図したとおりにexacly動作するように思われます!それに感謝します。私も違いを見るためにActivator.CreateInstanceなどconstructorInfo.Invokeと構築されたSOMのパフォーマンステストを使用して実装を行った実験の便宜上 ...
00:00:00.9246614, Actiator
00:00:00.7524483, Constructor Invoke
00:00:00.8235814, Compiled Expression
このテストでは、100個の000インスタンスの作成を時限それぞれのメソッドを使用して同じ型を作成し、結果を出力します。私はコンストラクタがメソッドの継ぎ目をよりよく実行するのを見るのが少し奨励されました!
[リフレクションを使用して型を動的にインスタンス化する方法](https://stackoverflow.com/questions/5493881/how-to-instantiate-a-type-dynamically-using-reflection) – rmjoia
リフレクションはありません私は何をしています。 –
ああ、私の悪い、私はGetTypeNameFromSomwhere()を見た...まあ、文字列から型をインスタンス化すると、データベースのプロセスのIDを取得していました。そのIDによって、新しい型をインスタンス化していました。 文字列からインスタンス化する方法があります。 :p – rmjoia