发布一个用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);
        }


    }

posted on 2008-05-23 21:17  henry  阅读(2553)  评论(5编辑  收藏  举报

导航