0

我想用 C# IL 实现一个浅拷贝,而不是直接反射。

• ShallowCopy 版本直接反射:

    public T ShallowCopy<T>(T instanceToShallowCopy) where T : class
    {
        Type type = instanceToShallowCopy.GetType();

        T result;
        try
        {
            result = System.Activator.CreateInstance(type) as T;
        }
        catch (MissingMethodException ex)
        {
            throw new MissingMethodException("The input instance type should contain default constructor.", ex);
        }
        catch (AggregateException ex)
        {
            throw new AggregateException("Activator create instance failed.", ex);
        }

        foreach (System.Reflection.PropertyInfo propertyInfo in instanceToShallowCopy.GetType().GetProperties())
        {
            if(propertyInfo.GetIndexParameters().Length == 0)
            {
                Object value = propertyInfo.GetValue(instanceToShallowCopy);
                propertyInfo.SetValue(result, value);
            }
        }

        foreach (System.Reflection.FieldInfo fieldInfo in instanceToShallowCopy.GetType().GetFields())
        {
            Object value = fieldInfo.GetValue(instanceToShallowCopy);
            fieldInfo.SetValue(result, value);
        }

        return result;
    }           

• 我当前的 IL 版本代码是:

public static class PluginShallowCopyInvoker
{
    public delegate Object ShallowCopyDelegate(Object paramType);

    /// <summary>
    /// Dictionary to cache any params fast constructor invokers, by type. Each entry is a shallowcopy delegates. 
    /// </summary>
    private static ConcurrentDictionary<Type, ShallowCopyDelegate> InvokerCacheDictionary = new ConcurrentDictionary<Type, ShallowCopyDelegate>();

    /// <summary>
    /// T
    /// </summary>
    /// <param name="type"></param>
    /// <param name="instanceToShallowCopy"></param>
    /// <returns></returns>
    public static ShallowCopyDelegate GenerateShallowCopyInvoker(Type type, Object instanceToShallowCopy)
    {
        ShallowCopyDelegate shallowCopyDelegate = null;
        if (!InvokerCacheDictionary.TryGetValue(type, out shallowCopyDelegate))
        {
            shallowCopyDelegate = BuildShallwCopyInvokersForType(type, instanceToShallowCopy);
            InvokerCacheDictionary.TryAdd(type, shallowCopyDelegate);
        }
        return shallowCopyDelegate;
    }

    /// <summary>
    /// This is intent for do shallow copy, but now only create constructor. I don’t know how to do field/property copy.
    /// </summary>
    /// <param name="type"></param>
    /// <param name="instanceToShallowCopy"></param>
    /// <returns></returns>
    private static ShallowCopyDelegate BuildShallwCopyInvokersForType(Type type, Object instanceToShallowCopy)
    {
        var invokeMethod = new DynamicMethod("PISC_" + type.FullName, typeof(Object), new Type[]{typeof(Object)}, true);
        var ilgen = invokeMethod.GetILGenerator();
        var cinfo = type.GetConstructor(Type.EmptyTypes);

        if (cinfo == null) return null;

        ilgen.Emit(OpCodes.Newobj, cinfo);

        ilgen.Emit(OpCodes.Ret);

          // I don’t know how to do field/property copy here … hope can got your help ~~~


        return (ShallowCopyDelegate)invokeMethod.CreateDelegate(typeof(ShallowCopyDelegate));
    }


    public static void SetField(Type type, Object instanceToShallowCopy, ref Object newInstance)
    {
        foreach (System.Reflection.FieldInfo fieldInfo in instanceToShallowCopy.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance))
        {
            DynamicMethod dm = new DynamicMethod("setter", typeof(void), new Type[] { typeof(object), typeof(object) }, type, true);
            ILGenerator setGenerator = dm.GetILGenerator();

            setGenerator.Emit(OpCodes.Ldarg_0);
            setGenerator.Emit(OpCodes.Unbox, type);
            setGenerator.Emit(OpCodes.Ldarg_1);
            if (fieldInfo.FieldType.IsValueType)
            {
                setGenerator.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType);
            }
            else
            {
                setGenerator.Emit(OpCodes.Unbox, fieldInfo.FieldType);
            }

            setGenerator.Emit(OpCodes.Stfld, fieldInfo);
            setGenerator.Emit(OpCodes.Ret);

            var value = fieldInfo.GetValue(instanceToShallowCopy);
            newInstance = dm.Invoke(null, new object[]{newInstance, value});
        }
    }

我只知道如何构造一个实例,但我不知道如何复制他人的字段或属性。

有人可以帮我吗?

如果你能帮助我,真的很感激?

4

0 回答 0