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)]
45 public abstract class Delegate : ICloneable, ISerializable
47 private Type target_type;
48 private object m_target;
49 private string method_name;
50 private IntPtr method_ptr;
51 private IntPtr delegate_trampoline;
52 private MethodInfo method_info;
54 protected Delegate (object target, string method)
57 throw new ArgumentNullException ("target");
60 throw new ArgumentNullException ("method");
62 this.target_type = null;
63 this.method_ptr = IntPtr.Zero;
64 this.m_target = target;
65 this.method_name = method;
68 protected Delegate (Type target, string method)
71 throw new ArgumentNullException ("target");
74 throw new ArgumentNullException ("method");
76 this.target_type = target;
77 this.method_ptr = IntPtr.Zero;
79 this.method_name = method;
82 public MethodInfo Method {
88 public object Target {
98 [MethodImplAttribute (MethodImplOptions.InternalCall)]
99 internal static extern Delegate CreateDelegate_internal (Type type, object target, MethodInfo info);
106 static Delegate CreateDelegate (Type type, MethodInfo method, bool throwOnBindFailure)
109 throw new ArgumentNullException ("type");
112 throw new ArgumentNullException ("method");
114 if (!type.IsSubclassOf (typeof (MulticastDelegate)))
115 throw new ArgumentException ("type is not a subclass of Multicastdelegate");
117 if (!method.IsStatic)
118 if (throwOnBindFailure)
119 throw new ArgumentException ("The method should be static.", "method");
123 MethodInfo invoke = type.GetMethod ("Invoke");
125 // FIXME: Check the return type on the 1.0 profile as well
127 Type returnType = method.ReturnType;
128 Type delReturnType = invoke.ReturnType;
129 bool returnMatch = returnType == delReturnType;
132 // Delegate covariance
133 if (!delReturnType.IsValueType && (delReturnType != typeof (ValueType)) && (delReturnType.IsAssignableFrom (returnType)))
138 if (throwOnBindFailure)
139 throw new ArgumentException ("method return type is incompatible");
144 ParameterInfo[] delargs = invoke.GetParameters ();
145 ParameterInfo[] args = method.GetParameters ();
147 if (args.Length != delargs.Length)
148 if (throwOnBindFailure)
149 throw new ArgumentException ("method argument length mismatch");
153 int length = delargs.Length;
154 for (int i = 0; i < length; i++) {
155 bool match = delargs [i].ParameterType == args [i].ParameterType;
158 // Delegate contravariance
160 Type argType = delargs [i].ParameterType;
162 if (!argType.IsValueType && (argType != typeof (ValueType)) && (args [i].ParameterType.IsAssignableFrom (argType)))
168 if (throwOnBindFailure)
169 throw new ArgumentException ("method arguments are incompatible");
174 return CreateDelegate_internal (type, null, method);
177 public static Delegate CreateDelegate (Type type, MethodInfo method) {
178 return CreateDelegate (type, method, true);
186 static Delegate CreateDelegate (Type type, object target, MethodInfo method, bool throwOnBindFailure)
189 throw new ArgumentNullException ("type");
192 throw new ArgumentNullException ("method");
194 if (!type.IsSubclassOf (typeof (MulticastDelegate)))
195 throw new ArgumentException ("type is not a subclass of Multicastdelegate");
197 return CreateDelegate_internal (type, target, method);
206 static Delegate CreateDelegate (Type type, object target, MethodInfo method) {
207 return CreateDelegate (type, target, method, true);
210 public static Delegate CreateDelegate (Type type, object target, string method)
212 return CreateDelegate(type, target, method, false);
215 public static Delegate CreateDelegate (Type type, Type target, string method)
218 throw new ArgumentNullException ("type");
221 throw new ArgumentNullException ("target");
224 throw new ArgumentNullException ("method");
226 if (!type.IsSubclassOf (typeof (MulticastDelegate)))
227 throw new ArgumentException ("type is not subclass of MulticastDelegate.");
229 ParameterInfo[] delargs = type.GetMethod ("Invoke").GetParameters ();
230 Type[] delargtypes = new Type [delargs.Length];
232 for (int i=0; i<delargs.Length; i++)
233 delargtypes [i] = delargs [i].ParameterType;
236 * FIXME: we should check the caller has reflection permission
237 * or if it lives in the same assembly...
239 BindingFlags flags = BindingFlags.ExactBinding | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic;
240 MethodInfo info = target.GetMethod (method, flags, null, delargtypes, new ParameterModifier [0]);
243 throw new ArgumentException ("Couldn't bind to method.");
245 return CreateDelegate_internal (type, null, info);
253 static Delegate CreateDelegate (Type type, object target, string method, bool ignoreCase, bool throwOnBindFailure)
256 throw new ArgumentNullException ("type");
259 throw new ArgumentNullException ("target");
262 throw new ArgumentNullException ("method");
264 if (!type.IsSubclassOf (typeof (MulticastDelegate)))
265 throw new ArgumentException ("type");
267 ParameterInfo[] delargs = type.GetMethod ("Invoke").GetParameters ();
268 Type[] delargtypes = new Type [delargs.Length];
270 for (int i=0; i<delargs.Length; i++)
271 delargtypes [i] = delargs [i].ParameterType;
274 * FIXME: we should check the caller has reflection permission
275 * or if it lives in the same assembly...
277 BindingFlags flags = BindingFlags.ExactBinding | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
280 flags |= BindingFlags.IgnoreCase;
282 MethodInfo info = target.GetType ().GetMethod (method, flags, null, delargtypes, new ParameterModifier [0]);
285 if (throwOnBindFailure)
286 throw new ArgumentException ("Couldn't bind to method '" + method + "'.");
290 return CreateDelegate_internal (type, target, info);
293 public static Delegate CreateDelegate (Type type, object target, string method, bool ignoreCase) {
294 return CreateDelegate (type, target, method, ignoreCase, true);
297 public object DynamicInvoke (object[] args)
299 return DynamicInvokeImpl (args);
302 protected virtual object DynamicInvokeImpl (object[] args)
304 if (Method == null) {
305 Type[] mtypes = new Type [args.Length];
306 for (int i = 0; i < args.Length; ++i) {
307 mtypes [i] = args [i].GetType ();
309 method_info = m_target.GetType ().GetMethod (method_name, mtypes);
313 if ((m_target != null) && Method.IsStatic) {
314 // The delegate is bound to m_target
316 object[] newArgs = new object [args.Length + 1];
317 args.CopyTo (newArgs, 1);
318 newArgs [0] = m_target;
321 args = new object [] { m_target };
323 return Method.Invoke (null, args);
327 return Method.Invoke (m_target, args);
330 public virtual object Clone ()
332 return MemberwiseClone ();
335 public override bool Equals (object obj)
337 Delegate d = obj as Delegate;
342 // Do not compare method_ptr, since it can point to a trampoline
343 if ((d.target_type == target_type) && (d.m_target == m_target) &&
344 (d.method_name == method_name) && (d.method_info == method_info))
350 public override int GetHashCode ()
352 // FIXME: Sync with Equals above
353 return (int)method_ptr;
356 protected virtual MethodInfo GetMethodImpl ()
361 // This is from ISerializable
362 public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
364 DelegateSerializationHolder.GetDelegateData (this, info, context);
367 public virtual Delegate[] GetInvocationList()
369 return new Delegate[] { this };
373 /// Returns a new MulticastDelegate holding the
374 /// concatenated invocation lists of MulticastDelegates a and b
376 public static Delegate Combine (Delegate a, Delegate b)
386 if (a.GetType () != b.GetType ())
387 throw new ArgumentException (Locale.GetText ("Incompatible Delegate Types."));
389 return a.CombineImpl (b);
393 /// Returns a new MulticastDelegate holding the
394 /// concatenated invocation lists of an Array of MulticastDelegates
396 public static Delegate Combine (Delegate[] delegates)
398 if (delegates == null)
401 Delegate retval = null;
403 foreach (Delegate next in delegates)
404 retval = Combine (retval, next);
409 protected virtual Delegate CombineImpl (Delegate d)
411 throw new MulticastNotSupportedException ("");
414 public static Delegate Remove (Delegate source, Delegate value)
419 return source.RemoveImpl (value);
422 protected virtual Delegate RemoveImpl (Delegate d)
430 public static Delegate RemoveAll (Delegate source, Delegate value)
432 Delegate tmp = source;
433 while ((source = Delegate.Remove (source, value)) != tmp)
439 public static bool operator == (Delegate a, Delegate b)
441 if ((object)a == null) {
442 if ((object)b == null)
445 } else if ((object) b == null)
451 public static bool operator != (Delegate a, Delegate b)