发布一个用Emit实现的对象创建工厂
经常用反射创建对象的朋友一定用过Activator.CreateInstance方法,这段时间在学习IL用Emit也实现了这样一个功能,也支持多不同参数的构造。
不过动太方法的key构造并不理想所以在性能上有所损耗,但其性能还是优胜于Activator.CreateInstance方法。
以下是测试代码和工厂代码
public delegate object CreateInstanceHandler(object[] parameters);
public class Program
{
public Program()
{
}
public Program(int i)
{
}
public Program(int i, string name)
{
}
static void Main(string[] args)
{
Program p;
p = Activator.CreateInstance<Program>();
p = CreateObjectFactory.CreateInstance<Program>();
p = (Program)Activator.CreateInstance(typeof(Program), new object[] { 2 });
p = CreateObjectFactory.CreateInstance<Program>(new object[] { 2 });
p = (Program)Activator.CreateInstance(typeof(Program), new object[] { 2, "henry" });
p = CreateObjectFactory.CreateInstance<Program>(new object[] { 2, "henry" });
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
for (int i = 0; i < 10; i++)
{
sw.Reset();
sw.Start();
p = Activator.CreateInstance<Program>();
p = (Program)Activator.CreateInstance(typeof(Program), new object[] { 2 });
p = (Program)Activator.CreateInstance(typeof(Program), new object[] { 2, "henry" });
sw.Stop();
Console.WriteLine("Reflection:\t" + sw.Elapsed.TotalMilliseconds);
sw.Reset();
sw.Start();
p = CreateObjectFactory.CreateInstance<Program>();
p = CreateObjectFactory.CreateInstance<Program>(new object[] { 2 });
p = CreateObjectFactory.CreateInstance<Program>(new object[] { 2, "henry" });
sw.Stop();
Console.WriteLine("Emit:\t" + sw.Elapsed.TotalMilliseconds);
}
Console.Read();
}
}
public class CreateObjectFactory
{
public static T CreateInstance<T>()
{
return CreateInstance<T>(null);
}
static Dictionary<string, CreateInstanceHandler> mHandlers = new Dictionary<string, CreateInstanceHandler>();
public static T CreateInstance<T>(params object[] parameters)
{
Type objtype = typeof(T);
Type[] ptypes = GetParameterTypes(parameters);
string key = typeof(T).FullName + "_" + GetKey(ptypes);
if (!mHandlers.ContainsKey(key))
{
CreateHandler(objtype, key, ptypes);
}
return (T)mHandlers[key](parameters);
}
static void CreateHandler(Type objtype, string key, Type[] ptypes)
{
lock (typeof(CreateObjectFactory))
{
if (!mHandlers.ContainsKey(key))
{
DynamicMethod dm = new DynamicMethod(key, typeof(object), new Type[] { typeof(object[]) }, typeof(CreateObjectFactory).Module);
ILGenerator il = dm.GetILGenerator();
ConstructorInfo cons = objtype.GetConstructor(ptypes);
il.Emit(OpCodes.Nop);
for (int i = 0; i < ptypes.Length; i++)
{
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldc_I4, i);
il.Emit(OpCodes.Ldelem_Ref);
if (ptypes[i].IsValueType)
{
il.Emit(OpCodes.Unbox_Any, ptypes[i]);
}
else
{
il.Emit(OpCodes.Castclass, ptypes[i]);
}
}
il.Emit(OpCodes.Newobj, cons);
il.Emit(OpCodes.Ret);
CreateInstanceHandler ci = (CreateInstanceHandler)dm.CreateDelegate(typeof(CreateInstanceHandler));
mHandlers.Add(key, ci);
}
}
}
static Type[] GetParameterTypes(params object[] parameters)
{
if (parameters == null)
return new Type[0];
Type[] values = new Type[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
values[i] = parameters[i].GetType();
}
return values;
}
static string GetKey(params Type[] types)
{
if (types == null || types.Length == 0)
return "null";
return string.Concat(types);
}
}
public class Program
{
public Program()
{
}
public Program(int i)
{
}
public Program(int i, string name)
{
}
static void Main(string[] args)
{
Program p;
p = Activator.CreateInstance<Program>();
p = CreateObjectFactory.CreateInstance<Program>();
p = (Program)Activator.CreateInstance(typeof(Program), new object[] { 2 });
p = CreateObjectFactory.CreateInstance<Program>(new object[] { 2 });
p = (Program)Activator.CreateInstance(typeof(Program), new object[] { 2, "henry" });
p = CreateObjectFactory.CreateInstance<Program>(new object[] { 2, "henry" });
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
for (int i = 0; i < 10; i++)
{
sw.Reset();
sw.Start();
p = Activator.CreateInstance<Program>();
p = (Program)Activator.CreateInstance(typeof(Program), new object[] { 2 });
p = (Program)Activator.CreateInstance(typeof(Program), new object[] { 2, "henry" });
sw.Stop();
Console.WriteLine("Reflection:\t" + sw.Elapsed.TotalMilliseconds);
sw.Reset();
sw.Start();
p = CreateObjectFactory.CreateInstance<Program>();
p = CreateObjectFactory.CreateInstance<Program>(new object[] { 2 });
p = CreateObjectFactory.CreateInstance<Program>(new object[] { 2, "henry" });
sw.Stop();
Console.WriteLine("Emit:\t" + sw.Elapsed.TotalMilliseconds);
}
Console.Read();
}
}
public class CreateObjectFactory
{
public static T CreateInstance<T>()
{
return CreateInstance<T>(null);
}
static Dictionary<string, CreateInstanceHandler> mHandlers = new Dictionary<string, CreateInstanceHandler>();
public static T CreateInstance<T>(params object[] parameters)
{
Type objtype = typeof(T);
Type[] ptypes = GetParameterTypes(parameters);
string key = typeof(T).FullName + "_" + GetKey(ptypes);
if (!mHandlers.ContainsKey(key))
{
CreateHandler(objtype, key, ptypes);
}
return (T)mHandlers[key](parameters);
}
static void CreateHandler(Type objtype, string key, Type[] ptypes)
{
lock (typeof(CreateObjectFactory))
{
if (!mHandlers.ContainsKey(key))
{
DynamicMethod dm = new DynamicMethod(key, typeof(object), new Type[] { typeof(object[]) }, typeof(CreateObjectFactory).Module);
ILGenerator il = dm.GetILGenerator();
ConstructorInfo cons = objtype.GetConstructor(ptypes);
il.Emit(OpCodes.Nop);
for (int i = 0; i < ptypes.Length; i++)
{
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldc_I4, i);
il.Emit(OpCodes.Ldelem_Ref);
if (ptypes[i].IsValueType)
{
il.Emit(OpCodes.Unbox_Any, ptypes[i]);
}
else
{
il.Emit(OpCodes.Castclass, ptypes[i]);
}
}
il.Emit(OpCodes.Newobj, cons);
il.Emit(OpCodes.Ret);
CreateInstanceHandler ci = (CreateInstanceHandler)dm.CreateDelegate(typeof(CreateInstanceHandler));
mHandlers.Add(key, ci);
}
}
}
static Type[] GetParameterTypes(params object[] parameters)
{
if (parameters == null)
return new Type[0];
Type[] values = new Type[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
values[i] = parameters[i].GetType();
}
return values;
}
static string GetKey(params Type[] types)
{
if (types == null || types.Length == 0)
return "null";
return string.Concat(types);
}
}