5 // Miguel de Icaza (miguel@ximian.com)
6 // Daniel Stodden (stodden@in.tum.de)
7 // Dietmar Maurer (dietmar@ximian.com)
9 // (C) Ximian, Inc. http://www.ximian.com
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System.Reflection;
36 using System.Runtime.Serialization;
37 using System.Runtime.CompilerServices;
38 using System.Runtime.InteropServices;
43 [ClassInterface (ClassInterfaceType.AutoDual)]
46 [System.Runtime.InteropServices.ComVisible (true)]
49 public abstract class Delegate : ICloneable, ISerializable
51 private Type target_type;
52 private object m_target;
53 private string method_name;
54 private IntPtr method_ptr;
55 private IntPtr delegate_trampoline;
56 private MethodInfo method_info;
58 protected Delegate (object target, string method)
61 throw new ArgumentNullException ("target");
64 throw new ArgumentNullException ("method");
66 this.target_type = null;
67 this.method_ptr = IntPtr.Zero;
68 this.m_target = target;
69 this.method_name = method;
72 protected Delegate (Type target, string method)
75 throw new ArgumentNullException ("target");
78 throw new ArgumentNullException ("method");
80 this.target_type = target;
81 this.method_ptr = IntPtr.Zero;
83 this.method_name = method;
86 public MethodInfo Method {
92 public object Target {
102 [MethodImplAttribute (MethodImplOptions.InternalCall)]
103 internal static extern Delegate CreateDelegate_internal (Type type, object target, MethodInfo info);
110 static Delegate CreateDelegate (Type type, MethodInfo method, bool throwOnBindFailure)
113 throw new ArgumentNullException ("type");
116 throw new ArgumentNullException ("method");
118 if (!type.IsSubclassOf (typeof (MulticastDelegate)))
119 throw new ArgumentException ("type is not a subclass of Multicastdelegate");
121 if (!method.IsStatic)
122 if (throwOnBindFailure)
123 throw new ArgumentException ("The method should be static.", "method");
127 MethodInfo invoke = type.GetMethod ("Invoke");
129 // FIXME: Check the return type on the 1.0 profile as well
131 Type returnType = method.ReturnType;
132 Type delReturnType = invoke.ReturnType;
133 bool returnMatch = returnType == delReturnType;
136 // Delegate covariance
137 if (!delReturnType.IsValueType && (delReturnType != typeof (ValueType)) && (delReturnType.IsAssignableFrom (returnType)))
142 if (throwOnBindFailure)
143 throw new ArgumentException ("method return type is incompatible");
148 ParameterInfo[] delargs = invoke.GetParameters ();
149 ParameterInfo[] args = method.GetParameters ();
151 if (args.Length != delargs.Length)
152 if (throwOnBindFailure)
153 throw new ArgumentException ("method argument length mismatch");
157 int length = delargs.Length;
158 for (int i = 0; i < length; i++) {
159 bool match = delargs [i].ParameterType == args [i].ParameterType;
162 // Delegate contravariance
164 Type argType = delargs [i].ParameterType;
166 if (!argType.IsValueType && (argType != typeof (ValueType)) && (args [i].ParameterType.IsAssignableFrom (argType)))
172 if (throwOnBindFailure)
173 throw new ArgumentException ("method arguments are incompatible");
178 return CreateDelegate_internal (type, null, method);
181 public static Delegate CreateDelegate (Type type, MethodInfo method) {
182 return CreateDelegate (type, method, true);
190 static Delegate CreateDelegate (Type type, object target, MethodInfo method, bool throwOnBindFailure)
193 throw new ArgumentNullException ("type");
196 throw new ArgumentNullException ("method");
198 if (!type.IsSubclassOf (typeof (MulticastDelegate)))
199 throw new ArgumentException ("type is not a subclass of Multicastdelegate");
201 return CreateDelegate_internal (type, target, method);
210 static Delegate CreateDelegate (Type type, object target, MethodInfo method) {
211 return CreateDelegate (type, target, method, true);
214 public static Delegate CreateDelegate (Type type, object target, string method)
216 return CreateDelegate(type, target, method, false);
219 public static Delegate CreateDelegate (Type type, Type target, string method)
222 throw new ArgumentNullException ("type");
225 throw new ArgumentNullException ("target");
228 throw new ArgumentNullException ("method");
230 if (!type.IsSubclassOf (typeof (MulticastDelegate)))
231 throw new ArgumentException ("type is not subclass of MulticastDelegate.");
233 ParameterInfo[] delargs = type.GetMethod ("Invoke").GetParameters ();
234 Type[] delargtypes = new Type [delargs.Length];
236 for (int i=0; i<delargs.Length; i++)
237 delargtypes [i] = delargs [i].ParameterType;
240 * FIXME: we should check the caller has reflection permission
241 * or if it lives in the same assembly...
243 BindingFlags flags = BindingFlags.ExactBinding | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic;
244 MethodInfo info = target.GetMethod (method, flags, null, delargtypes, new ParameterModifier [0]);
247 throw new ArgumentException ("Couldn't bind to method.");
249 return CreateDelegate_internal (type, null, info);
257 static Delegate CreateDelegate (Type type, object target, string method, bool ignoreCase, bool throwOnBindFailure)
260 throw new ArgumentNullException ("type");
263 throw new ArgumentNullException ("target");
266 throw new ArgumentNullException ("method");
268 if (!type.IsSubclassOf (typeof (MulticastDelegate)))
269 throw new ArgumentException ("type");
271 ParameterInfo[] delargs = type.GetMethod ("Invoke").GetParameters ();
272 Type[] delargtypes = new Type [delargs.Length];
274 for (int i=0; i<delargs.Length; i++)
275 delargtypes [i] = delargs [i].ParameterType;
278 * FIXME: we should check the caller has reflection permission
279 * or if it lives in the same assembly...
281 BindingFlags flags = BindingFlags.ExactBinding | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
284 flags |= BindingFlags.IgnoreCase;
286 MethodInfo info = target.GetType ().GetMethod (method, flags, null, delargtypes, new ParameterModifier [0]);
289 if (throwOnBindFailure)
290 throw new ArgumentException ("Couldn't bind to method '" + method + "'.");
294 return CreateDelegate_internal (type, target, info);
297 public static Delegate CreateDelegate (Type type, object target, string method, bool ignoreCase) {
298 return CreateDelegate (type, target, method, ignoreCase, true);
302 public object DynamicInvoke (params object[] args)
304 public object DynamicInvoke (object[] args)
307 return DynamicInvokeImpl (args);
310 protected virtual object DynamicInvokeImpl (object[] args)
312 if (Method == null) {
313 Type[] mtypes = new Type [args.Length];
314 for (int i = 0; i < args.Length; ++i) {
315 mtypes [i] = args [i].GetType ();
317 method_info = m_target.GetType ().GetMethod (method_name, mtypes);
321 if ((m_target != null) && Method.IsStatic) {
322 // The delegate is bound to m_target
324 object[] newArgs = new object [args.Length + 1];
325 args.CopyTo (newArgs, 1);
326 newArgs [0] = m_target;
329 args = new object [] { m_target };
331 return Method.Invoke (null, args);
335 return Method.Invoke (m_target, args);
338 public virtual object Clone ()
340 return MemberwiseClone ();
343 public override bool Equals (object obj)
345 Delegate d = obj as Delegate;
350 // Do not compare method_ptr, since it can point to a trampoline
351 if ((d.target_type == target_type) && (d.m_target == m_target) &&
352 (d.method_name == method_name) && (d.method_info == method_info))
358 public override int GetHashCode ()
360 // FIXME: Sync with Equals above
361 return (int)method_ptr;
364 protected virtual MethodInfo GetMethodImpl ()
369 // This is from ISerializable
370 public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
372 DelegateSerializationHolder.GetDelegateData (this, info, context);
375 public virtual Delegate[] GetInvocationList()
377 return new Delegate[] { this };
381 /// Returns a new MulticastDelegate holding the
382 /// concatenated invocation lists of MulticastDelegates a and b
384 public static Delegate Combine (Delegate a, Delegate b)
394 if (a.GetType () != b.GetType ())
395 throw new ArgumentException (Locale.GetText ("Incompatible Delegate Types."));
397 return a.CombineImpl (b);
401 /// Returns a new MulticastDelegate holding the
402 /// concatenated invocation lists of an Array of MulticastDelegates
405 [System.Runtime.InteropServices.ComVisible (true)]
406 public static Delegate Combine (params Delegate[] delegates)
408 public static Delegate Combine (Delegate[] delegates)
411 if (delegates == null)
414 Delegate retval = null;
416 foreach (Delegate next in delegates)
417 retval = Combine (retval, next);
422 protected virtual Delegate CombineImpl (Delegate d)
424 throw new MulticastNotSupportedException ("");
427 public static Delegate Remove (Delegate source, Delegate value)
432 return source.RemoveImpl (value);
435 protected virtual Delegate RemoveImpl (Delegate d)
443 public static Delegate RemoveAll (Delegate source, Delegate value)
445 Delegate tmp = source;
446 while ((source = Delegate.Remove (source, value)) != tmp)
452 public static bool operator == (Delegate a, Delegate b)
454 if ((object)a == null) {
455 if ((object)b == null)
458 } else if ((object) b == null)
464 public static bool operator != (Delegate a, Delegate b)