0

I want to implement a shallow copy with C# IL instead of reflection directly.

• ShallowCopy version with reflection directly:

    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;
    }           

• My current IL version code is :

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});
        }
    }

I just know how to construct an instance but I have no idea on how to copy other’s field or propers.

Could anyone help me on this ?

Really appreciate if you can help me?

Jason Cai
  • 1
  • 1
  • 1
  • 2
  • 2
    Properties are a terrible way to clone. Just call `MemberwiseClone` via reflection. MIght be possible with `DynamicMethod` too to call it. – leppie Jul 17 '15 at 14:28
  • 1
    @leppie Easier with `Delegate.CreateDelegate`... https://ideone.com/foe6iv – xanatos Jul 17 '15 at 14:57
  • @xanatos: Mono is so broken... ;p – leppie Jul 17 '15 at 16:38
  • 1
    @leppie It works even on .NET 4.0-4.5 (just tested it) (I didn't test it on .NET < 4.0) – xanatos Jul 17 '15 at 17:50
  • @xanatos: I guess there are no restrictions then in full trust mode. Mind testing in medium trust mode? In both mono and MS? – leppie Jul 17 '15 at 18:05
  • @leppie on dotnetfiddle it doesn't work, giving an exception with `System.Security.SecurityException: Request for the permission of type 'System.Security.Permissions.ReflectionPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.`... I don't have Mono on this PC. – xanatos Jul 17 '15 at 20:04
  • @xanatos Yeah, both CreateDelegate and DynamicMethod calls check if the call is possible using the security permissions. It's protected, so it'll fail; still, simply using `Invoke` should work (I guess that should even work on Mono AOT). – atlaste Jul 20 '15 at 06:59

0 Answers0