New test.
[mono.git] / mcs / class / corlib / System / Delegate.cs
index 9d5964696c3bf237012653ae1ba6a6742bcd56fa..733eac9a4d3f132eab175fecdeed571364b4145f 100644 (file)
 //
 
 using System.Reflection;
+using System.Runtime.Remoting;
 using System.Runtime.Serialization;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 
 namespace System
 {
-#if NET_1_1
+       /* Contains the rarely used fields of Delegate */
+       class DelegateData {
+               public Type target_type;
+               public string method_name;
+       }
+
        [ClassInterface (ClassInterfaceType.AutoDual)]
-#endif
-#if NET_2_0
        [System.Runtime.InteropServices.ComVisible (true)]
        [Serializable]
-#endif
        public abstract class Delegate : ICloneable, ISerializable
        {
                #region Sync with object-internals.h
+#pragma warning disable 169, 414, 649
                private IntPtr method_ptr;
                private IntPtr invoke_impl;
                private object m_target;
                private IntPtr method;
-               private Type target_type;
-               private string method_name;
                private IntPtr delegate_trampoline;
+               private IntPtr method_code;
                private MethodInfo method_info;
 
                // Keep a ref of the MethodInfo passed to CreateDelegate.
                // Used to keep DynamicMethods alive.
                private MethodInfo original_method_info;
+
+               private DelegateData data;
+#pragma warning restore 169, 414, 649
                #endregion
 
                protected Delegate (object target, string method)
@@ -71,10 +77,9 @@ namespace System
                        if (method == null)
                                throw new ArgumentNullException ("method");
 
-                       this.target_type = null;
-                       this.method_ptr = IntPtr.Zero;
                        this.m_target = target;
-                       this.method_name = method;
+                       this.data = new DelegateData ();
+                       this.data.method_name = method;
                }
 
                protected Delegate (Type target, string method)
@@ -85,10 +90,9 @@ namespace System
                        if (method == null)
                                throw new ArgumentNullException ("method");
 
-                       this.target_type = target;
-                       this.method_ptr = IntPtr.Zero;
-                       this.m_target = null;
-                       this.method_name = method;
+                       this.data = new DelegateData ();
+                       this.data.method_name = method;
+                       this.data.target_type = target;
                }
 
                public MethodInfo Method {
@@ -96,8 +100,9 @@ namespace System
                                if (method_info != null) {
                                        return method_info;
                                } else {
-                                       if (method != IntPtr.Zero)
-                                               method_info = (MethodInfo)MethodBase.GetMethodFromHandle (new RuntimeMethodHandle (method));
+                                       if (method != IntPtr.Zero) {
+                                               method_info = (MethodInfo)MethodBase.GetMethodFromHandleNoGenericCheck (new RuntimeMethodHandle (method));
+                                       }
                                        return method_info;
                                }
                        }
@@ -114,7 +119,7 @@ namespace System
                //
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               internal static extern Delegate CreateDelegate_internal (Type type, object target, MethodInfo info);
+               internal static extern Delegate CreateDelegate_internal (Type type, object target, MethodInfo info, bool throwOnBindFailure);
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                internal extern void SetMulticastInvoke ();
@@ -122,40 +127,31 @@ namespace System
                private static bool arg_type_match (Type delArgType, Type argType) {
                        bool match = delArgType == argType;
 
-#if NET_2_0
                        // Delegate contravariance
                        if (!match) {
-                               if (!delArgType.IsValueType && (delArgType != typeof (ValueType)) && (argType.IsAssignableFrom (delArgType)))
+                               if (!argType.IsValueType && argType.IsAssignableFrom (delArgType))
                                        match = true;
                        }
-#endif
+
                        return match;
                }
 
                private static bool return_type_match (Type delReturnType, Type returnType) {
                        bool returnMatch = returnType == delReturnType;
 
-#if NET_2_0
                        if (!returnMatch) {
                                // Delegate covariance
-                               if (!delReturnType.IsValueType && (delReturnType != typeof (ValueType)) && (delReturnType.IsAssignableFrom (returnType)))
+                               if (!returnType.IsValueType && delReturnType.IsAssignableFrom (returnType))
                                        returnMatch = true;
                        }
-#endif
 
                        return returnMatch;
                }
 
-#if NET_2_0
                public static Delegate CreateDelegate (Type type, object firstArgument, MethodInfo method, bool throwOnBindFailure)
-#else
-               internal static Delegate CreateDelegate (Type type, object target, MethodInfo method, bool throwOnBindFailure)
-#endif
                {
-#if NET_2_0
                        // The name of the parameter changed in 2.0
                        object target = firstArgument;
-#endif
 
                        if (type == null)
                                throw new ArgumentNullException ("type");
@@ -165,14 +161,6 @@ namespace System
 
                        if (!type.IsSubclassOf (typeof (MulticastDelegate)))
                                throw new ArgumentException ("type is not a subclass of Multicastdelegate");
-#if !NET_2_0
-                       if ((target == null) && !method.IsStatic) {
-                               if (throwOnBindFailure)
-                                       throw new ArgumentException ("The method should be static.", "method");
-                               else
-                                       return null;
-                       }
-#endif
 
                        MethodInfo invoke = type.GetMethod ("Invoke");
 
@@ -182,8 +170,6 @@ namespace System
                                else
                                        return null;
 
-                       // FIXME: Figure out how net 1.1 works
-#if NET_2_0
                        ParameterInfo[] delargs = invoke.GetParameters ();
                        ParameterInfo[] args = method.GetParameters ();
 
@@ -204,8 +190,13 @@ namespace System
                                        // as the 'this' argument to the method.
                                        //
                                        argLengthMatch = (args.Length + 1 == delargs.Length);
-                               else
+                               else {
                                        argLengthMatch = (args.Length == delargs.Length);
+
+                                       if (!argLengthMatch)
+                                               // closed over a null reference
+                                               argLengthMatch = args.Length == delargs.Length + 1;
+                               }
                        }
                        if (!argLengthMatch)
                                if (throwOnBindFailure)
@@ -231,9 +222,16 @@ namespace System
                                        for (int i = 0; i < args.Length; i++)
                                                argsMatch &= arg_type_match (delargs [i + 1].ParameterType, args [i].ParameterType);
                                } else {
-                                       argsMatch = true;
-                                       for (int i = 0; i < args.Length; i++)
-                                               argsMatch &= arg_type_match (delargs [i].ParameterType, args [i].ParameterType);
+                                       if (delargs.Length + 1 == args.Length) {
+                                               // closed over a null reference
+                                               argsMatch = !args [0].ParameterType.IsValueType;
+                                               for (int i = 0; i < delargs.Length; i++)
+                                                       argsMatch &= arg_type_match (delargs [i].ParameterType, args [i + 1].ParameterType);
+                                       } else {
+                                               argsMatch = true;
+                                               for (int i = 0; i < args.Length; i++)
+                                                       argsMatch &= arg_type_match (delargs [i].ParameterType, args [i].ParameterType);
+                                       }
                                }
                        }
 
@@ -242,28 +240,18 @@ namespace System
                                        throw new ArgumentException ("method arguments are incompatible");
                                else
                                        return null;
-#endif
 
-                       Delegate d = CreateDelegate_internal (type, target, method);
-                       d.original_method_info = method;
+                       Delegate d = CreateDelegate_internal (type, target, method, throwOnBindFailure);
+                       if (d != null)
+                               d.original_method_info = method;
                        return d;
                }
 
-#if NET_2_0
-               public
-#else
-               internal
-#endif
-               static Delegate CreateDelegate (Type type, object target, MethodInfo method) {
-                       return CreateDelegate (type, target, method, true);
+               public static Delegate CreateDelegate (Type type, object firstArgument, MethodInfo method) {
+                       return CreateDelegate (type, firstArgument, method, true);
                }
 
-#if NET_2_0
-               public
-#else
-               internal
-#endif
-               static Delegate CreateDelegate (Type type, MethodInfo method, bool throwOnBindFailure)
+               public static Delegate CreateDelegate (Type type, MethodInfo method, bool throwOnBindFailure)
                {
                        return CreateDelegate (type, null, method, throwOnBindFailure);
                }
@@ -333,12 +321,7 @@ namespace System
                        return info;
                }
 
-#if NET_2_0
-               public 
-#else
-               internal
-#endif
-               static Delegate CreateDelegate (Type type, Type target, string method, bool ignoreCase, bool throwOnBindFailure)
+               public static Delegate CreateDelegate (Type type, Type target, string method, bool ignoreCase, bool throwOnBindFailure)
                {
                        if (target == null)
                                throw new ArgumentNullException ("target");
@@ -348,25 +331,18 @@ namespace System
                        if (info == null)
                                return null;
 
-                       return CreateDelegate_internal (type, null, info);
+                       return CreateDelegate_internal (type, null, info, throwOnBindFailure);
                }
 
                public static Delegate CreateDelegate (Type type, Type target, string method) {
                        return CreateDelegate (type, target, method, false, true);
                }
 
-#if NET_2_0
                public static Delegate CreateDelegate (Type type, Type target, string method, bool ignoreCase) {
                        return CreateDelegate (type, target, method, ignoreCase, true);
                }
-#endif
 
-#if NET_2_0
-               public
-#else
-               internal
-#endif
-               static Delegate CreateDelegate (Type type, object target, string method, bool ignoreCase, bool throwOnBindFailure)
+               public static Delegate CreateDelegate (Type type, object target, string method, bool ignoreCase, bool throwOnBindFailure)
                {
                        if (target == null)
                                throw new ArgumentNullException ("target");
@@ -376,18 +352,14 @@ namespace System
                        if (info == null)
                                return null;
 
-                       return CreateDelegate_internal (type, target, info);
+                       return CreateDelegate_internal (type, target, info, throwOnBindFailure);
                }
 
                public static Delegate CreateDelegate (Type type, object target, string method, bool ignoreCase) {
                        return CreateDelegate (type, target, method, ignoreCase, true);
                }
 
-#if NET_2_0
                public object DynamicInvoke (params object[] args)
-#else
-               public object DynamicInvoke (object[] args)
-#endif
                {
                        return DynamicInvokeImpl (args);
                }
@@ -399,10 +371,9 @@ namespace System
                                for (int i = 0; i < args.Length; ++i) {
                                        mtypes [i] = args [i].GetType ();
                                }
-                               method_info = m_target.GetType ().GetMethod (method_name, mtypes);
+                               method_info = m_target.GetType ().GetMethod (data.method_name, mtypes);
                        }
 
-#if NET_2_0
                        if ((m_target != null) && Method.IsStatic) {
                                // The delegate is bound to m_target
                                if (args != null) {
@@ -415,7 +386,6 @@ namespace System
                                }
                                return Method.Invoke (null, args);
                        }
-#endif
 
                        return Method.Invoke (m_target, args);
                }
@@ -433,17 +403,23 @@ namespace System
                                return false;
                        
                        // Do not compare method_ptr, since it can point to a trampoline
-                       if ((d.target_type == target_type) && (d.m_target == m_target) &&
-                               (d.method_name == method_name) && (d.method == method))
+                       if (d.m_target == m_target && d.method == method) {
+                               if (d.data != null || data != null) {
+                                       /* Uncommon case */
+                                       if (d.data != null && data != null)
+                                               return (d.data.target_type == data.target_type && d.data.method_name == data.method_name);
+                                       else
+                                               return false;
+                               }
                                return true;
+                       }
 
                        return false;
                }
 
                public override int GetHashCode ()
                {
-                       // FIXME: Sync with Equals above
-                       return (int)method_ptr;
+                       return method.GetHashCode () ^ (m_target != null ? m_target.GetHashCode () : 0);
                }
 
                protected virtual MethodInfo GetMethodImpl ()
@@ -486,12 +462,8 @@ namespace System
                ///   Returns a new MulticastDelegate holding the
                ///   concatenated invocation lists of an Array of MulticastDelegates
                /// </symmary>
-#if NET_2_0
                [System.Runtime.InteropServices.ComVisible (true)]
                public static Delegate Combine (params Delegate[] delegates)
-#else
-               public static Delegate Combine (Delegate[] delegates)
-#endif
                {
                        if (delegates == null)
                                return null;
@@ -524,7 +496,7 @@ namespace System
 
                        return this;
                }
-#if NET_1_1
+
                public static Delegate RemoveAll (Delegate source, Delegate value)
                {
                        Delegate tmp = source;
@@ -533,22 +505,27 @@ namespace System
 
                        return tmp;
                }
-#endif
-               public static bool operator == (Delegate a, Delegate b)
+
+               public static bool operator == (Delegate d1, Delegate d2)
                {
-                       if ((object)a == null) {
-                               if ((object)b == null)
+                       if ((object)d1 == null) {
+                               if ((object)d2 == null)
                                        return true;
                                return false;
-                       } else if ((object) b == null)
+                       } else if ((object) d2 == null)
                                return false;
                        
-                       return a.Equals (b);
+                       return d1.Equals (d2);
+               }
+
+               public static bool operator != (Delegate d1, Delegate d2)
+               {
+                       return !(d1 == d2);
                }
 
-               public static bool operator != (Delegate a, Delegate b)
+               internal bool IsTransparentProxy ()
                {
-                       return !(a == b);
+                       return RemotingServices.IsTransparentProxy (m_target);
                }
        }
 }