Exemple #1
0
        protected T CreateDelegate()
        {
            var parameters = new List <Type> ();

            parameters.Add(this.GetType());
            parameters.AddRange(this.Method.GetParameters().Select(p => p.ParameterType));
            var method = new DynamicMethod("WeakDelegateDynamic", this.Method.ReturnType,
                                           parameters.ToArray(), this.GetType(), true);
            var hasReturnType = (this.Method.ReturnType != typeof(void));

            if (this.Method.IsGenericMethod)
            {
                method.MakeGenericMethod(this.Method.GetGenericArguments());
            }

            var il = method.GetILGenerator();

            // IL Code should be equivalent of...

            /*
             * var target = this.Reference.Target;
             * if (!CheckDelegate())
             *   return;
             *
             * return this.Method(args);
             *
             */

            // Create our labels
            var returnLabel = il.DefineLabel();
            var callLabel   = il.DefineLabel();

            // Define our local variables
            il.DeclareLocal(typeof(object));
            il.DeclareLocal(hasReturnType ? this.Method.ReturnType : typeof(int));
            il.DeclareLocal(typeof(bool));

            // Load the target value on to the stack to keep it alive
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, GetReferenceMethod);
            il.Emit(OpCodes.Callvirt, WeakReferenceGetTargetMethod);
            il.Emit(OpCodes.Stloc_0);

            // Call CheckDelegate
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, CheckDelegateMethod);
            il.Emit(OpCodes.Stloc_2);

            // If it did not return true then return immediately
            il.Emit(OpCodes.Ldloc_2);
            il.Emit(OpCodes.Brtrue_S, callLabel);
            il.Emit(OpCodes.Ldc_I4_0);
            il.Emit(OpCodes.Stloc_1);
            il.Emit(OpCodes.Br_S, returnLabel);

            // Load our target and all of our arguments
            il.MarkLabel(callLabel);
            il.Emit(OpCodes.Ldloc_0);
            for (int i = 0; i < this.Method.GetParameters().Length; i++)
            {
                il.Emit(OpCodes.Ldarg, i + 1);
            }

            // Call our method and return
            il.Emit(this.Method.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, this.Method);
            if (hasReturnType)
            {
                il.Emit(OpCodes.Stloc_1);
            }
            il.Emit(OpCodes.Br_S, returnLabel);
            il.MarkLabel(returnLabel);
            if (hasReturnType)
            {
                il.Emit(OpCodes.Ldloc_1);
            }
            il.Emit(OpCodes.Ret);

            return(method.CreateDelegate(this.Type, this) as T);
        }