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);
101 public static Delegate CreateDelegate (Type type, MethodInfo method)
104 throw new ArgumentNullException ("type");
107 throw new ArgumentNullException ("method");
109 if (!type.IsSubclassOf (typeof (MulticastDelegate)))
110 throw new ArgumentException ("type is not a subclass of Multicastdelegate");
112 if (!method.IsStatic)
113 throw new ArgumentException ("The method should be static.", "method");
115 MethodInfo invoke = type.GetMethod ("Invoke");
117 // FIXME: Check the return type on the 1.0 profile as well
119 Type returnType = method.ReturnType;
120 Type delReturnType = invoke.ReturnType;
121 bool returnMatch = returnType == delReturnType;
124 // Delegate covariance
125 if (!delReturnType.IsValueType && (delReturnType != typeof (ValueType)) && (delReturnType.IsAssignableFrom (returnType)))
130 throw new ArgumentException ("method return type is incompatible");
133 ParameterInfo[] delargs = invoke.GetParameters ();
134 ParameterInfo[] args = method.GetParameters ();
136 if (args.Length != delargs.Length)
137 throw new ArgumentException ("method argument length mismatch");
139 int length = delargs.Length;
140 for (int i = 0; i < length; i++) {
141 bool match = delargs [i].ParameterType == args [i].ParameterType;
144 // Delegate contravariance
146 Type argType = delargs [i].ParameterType;
148 if (!argType.IsValueType && (argType != typeof (ValueType)) && (args [i].ParameterType.IsAssignableFrom (argType)))
154 throw new ArgumentException ("method arguments are incompatible");
157 return CreateDelegate_internal (type, null, method);
165 static Delegate CreateDelegate (Type type, object target, MethodInfo method)
168 throw new ArgumentNullException ("type");
171 throw new ArgumentNullException ("method");
173 if (!type.IsSubclassOf (typeof (MulticastDelegate)))
174 throw new ArgumentException ("type is not a subclass of Multicastdelegate");
176 return CreateDelegate_internal (type, target, method);
180 public static Delegate CreateDelegate (Type type, object target, string method)
182 return CreateDelegate(type, target, method, false);
185 public static Delegate CreateDelegate (Type type, Type target, string method)
188 throw new ArgumentNullException ("type");
191 throw new ArgumentNullException ("target");
194 throw new ArgumentNullException ("method");
196 if (!type.IsSubclassOf (typeof (MulticastDelegate)))
197 throw new ArgumentException ("type is not subclass of MulticastDelegate.");
199 ParameterInfo[] delargs = type.GetMethod ("Invoke").GetParameters ();
200 Type[] delargtypes = new Type [delargs.Length];
202 for (int i=0; i<delargs.Length; i++)
203 delargtypes [i] = delargs [i].ParameterType;
206 * FIXME: we should check the caller has reflection permission
207 * or if it lives in the same assembly...
209 BindingFlags flags = BindingFlags.ExactBinding | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic;
210 MethodInfo info = target.GetMethod (method, flags, null, delargtypes, new ParameterModifier [0]);
213 throw new ArgumentException ("Couldn't bind to method.");
215 return CreateDelegate_internal (type, null, info);
218 public static Delegate CreateDelegate (Type type, object target, string method, bool ignoreCase)
221 throw new ArgumentNullException ("type");
224 throw new ArgumentNullException ("target");
227 throw new ArgumentNullException ("method");
229 if (!type.IsSubclassOf (typeof (MulticastDelegate)))
230 throw new ArgumentException ("type");
232 ParameterInfo[] delargs = type.GetMethod ("Invoke").GetParameters ();
233 Type[] delargtypes = new Type [delargs.Length];
235 for (int i=0; i<delargs.Length; i++)
236 delargtypes [i] = delargs [i].ParameterType;
239 * FIXME: we should check the caller has reflection permission
240 * or if it lives in the same assembly...
242 BindingFlags flags = BindingFlags.ExactBinding | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
245 flags |= BindingFlags.IgnoreCase;
247 MethodInfo info = target.GetType ().GetMethod (method, flags, null, delargtypes, new ParameterModifier [0]);
250 throw new ArgumentException ("Couldn't bind to method '" + method + "'.");
252 return CreateDelegate_internal (type, target, info);
255 public object DynamicInvoke (object[] args)
257 return DynamicInvokeImpl (args);
260 protected virtual object DynamicInvokeImpl (object[] args)
262 if (Method == null) {
263 Type[] mtypes = new Type [args.Length];
264 for (int i = 0; i < args.Length; ++i) {
265 mtypes [i] = args [i].GetType ();
267 method_info = m_target.GetType ().GetMethod (method_name, mtypes);
271 if ((m_target != null) && Method.IsStatic) {
272 // The delegate is bound to m_target
274 object[] newArgs = new object [args.Length + 1];
275 args.CopyTo (newArgs, 1);
276 newArgs [0] = m_target;
279 args = new object [] { m_target };
281 return Method.Invoke (null, args);
285 return Method.Invoke (m_target, args);
288 public virtual object Clone ()
290 return MemberwiseClone ();
293 public override bool Equals (object obj)
295 Delegate d = obj as Delegate;
300 // Do not compare method_ptr, since it can point to a trampoline
301 if ((d.target_type == target_type) && (d.m_target == m_target) &&
302 (d.method_name == method_name) && (d.method_info == method_info))
308 public override int GetHashCode ()
310 // FIXME: Sync with Equals above
311 return (int)method_ptr;
314 protected virtual MethodInfo GetMethodImpl ()
319 // This is from ISerializable
320 public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
322 DelegateSerializationHolder.GetDelegateData (this, info, context);
325 public virtual Delegate[] GetInvocationList()
327 return new Delegate[] { this };
331 /// Returns a new MulticastDelegate holding the
332 /// concatenated invocation lists of MulticastDelegates a and b
334 public static Delegate Combine (Delegate a, Delegate b)
344 if (a.GetType () != b.GetType ())
345 throw new ArgumentException (Locale.GetText ("Incompatible Delegate Types."));
347 return a.CombineImpl (b);
351 /// Returns a new MulticastDelegate holding the
352 /// concatenated invocation lists of an Array of MulticastDelegates
354 public static Delegate Combine (Delegate[] delegates)
356 if (delegates == null)
359 Delegate retval = null;
361 foreach (Delegate next in delegates)
362 retval = Combine (retval, next);
367 protected virtual Delegate CombineImpl (Delegate d)
369 throw new MulticastNotSupportedException ("");
372 public static Delegate Remove (Delegate source, Delegate value)
377 return source.RemoveImpl (value);
380 protected virtual Delegate RemoveImpl (Delegate d)
388 public static Delegate RemoveAll (Delegate source, Delegate value)
390 Delegate tmp = source;
391 while ((source = Delegate.Remove (source, value)) != tmp)
397 public static bool operator == (Delegate a, Delegate b)
399 if ((object)a == null) {
400 if ((object)b == null)
403 } else if ((object) b == null)
409 public static bool operator != (Delegate a, Delegate b)