* Makefile: Don't build make-map.exe.
[mono.git] / mcs / class / corlib / System / Delegate.cs
1 //
2 // System.Delegate.cs
3 //
4 // Authors:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Daniel Stodden (stodden@in.tum.de)
7 //   Dietmar Maurer (dietmar@ximian.com)
8 //
9 // (C) Ximian, Inc.  http://www.ximian.com
10 //
11
12 //
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 //
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:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
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.
33 //
34
35 using System.Reflection;
36 using System.Runtime.Serialization;
37 using System.Runtime.CompilerServices;
38 using System.Runtime.InteropServices;
39
40 namespace System
41 {
42 #if NET_1_1
43         [ClassInterface (ClassInterfaceType.AutoDual)]
44 #endif
45         public abstract class Delegate : ICloneable, ISerializable
46         {
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;
53
54                 protected Delegate (object target, string method)
55                 {
56                         if (target == null)
57                                 throw new ArgumentNullException ("target");
58
59                         if (method == null)
60                                 throw new ArgumentNullException ("method");
61
62                         this.target_type = null;
63                         this.method_ptr = IntPtr.Zero;
64                         this.m_target = target;
65                         this.method_name = method;
66                 }
67
68                 protected Delegate (Type target, string method)
69                 {
70                         if (target == null)
71                                 throw new ArgumentNullException ("target");
72
73                         if (method == null)
74                                 throw new ArgumentNullException ("method");
75
76                         this.target_type = target;
77                         this.method_ptr = IntPtr.Zero;
78                         this.m_target = null;
79                         this.method_name = method;
80                 }
81
82                 public MethodInfo Method {
83                         get {
84                                 return method_info;
85                         }
86                 }
87
88                 public object Target {
89                         get {
90                                 return m_target;
91                         }
92                 }
93
94                 //
95                 // Methods
96                 //
97
98                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
99                 internal static extern Delegate CreateDelegate_internal (Type type, object target, MethodInfo info);
100
101                 public static Delegate CreateDelegate (Type type, MethodInfo method)
102                 {
103                         if (type == null)
104                                 throw new ArgumentNullException ("type");
105
106                         if (method == null)
107                                 throw new ArgumentNullException ("method");
108
109                         if (!type.IsSubclassOf (typeof (MulticastDelegate)))
110                                 throw new ArgumentException ("type is not a subclass of Multicastdelegate");
111
112                         if (!method.IsStatic)
113                                 throw new ArgumentException ("The method should be static.", "method");
114
115                         MethodInfo invoke = type.GetMethod ("Invoke");
116
117                         // FIXME: Check the return type on the 1.0 profile as well
118 #if NET_2_0
119                         Type returnType = method.ReturnType;
120                         Type delReturnType = invoke.ReturnType;
121                         bool returnMatch = returnType == delReturnType;
122
123                         if (!returnMatch) {
124                                 // Delegate covariance
125                                 if (!delReturnType.IsValueType && (delReturnType != typeof (ValueType)) && (delReturnType.IsAssignableFrom (returnType)))
126                                         returnMatch = true;
127                         }
128
129                         if (!returnMatch)
130                                 throw new ArgumentException ("method return type is incompatible");
131 #endif
132
133                         ParameterInfo[] delargs = invoke.GetParameters ();
134                         ParameterInfo[] args = method.GetParameters ();
135
136                         if (args.Length != delargs.Length)
137                                 throw new ArgumentException ("method argument length mismatch");
138                         
139                         int length = delargs.Length;
140                         for (int i = 0; i < length; i++) {
141                                 bool match = delargs [i].ParameterType == args [i].ParameterType;
142
143 #if NET_2_0
144                                 // Delegate contravariance
145                                 if (!match) {
146                                         Type argType = delargs [i].ParameterType;
147
148                                         if (!argType.IsValueType && (argType != typeof (ValueType)) && (args [i].ParameterType.IsAssignableFrom (argType)))
149                                                 match = true;
150                                 }
151 #endif
152
153                                 if (!match)
154                                         throw new ArgumentException ("method arguments are incompatible");
155                         }
156
157                         return CreateDelegate_internal (type, null, method);
158                 }
159
160 #if NET_2_0
161                 public
162 #else
163                 internal
164 #endif
165                 static Delegate CreateDelegate (Type type, object target, MethodInfo method)
166                 {
167                         if (type == null)
168                                 throw new ArgumentNullException ("type");
169
170                         if (method == null)
171                                 throw new ArgumentNullException ("method");
172
173                         if (!type.IsSubclassOf (typeof (MulticastDelegate)))
174                                 throw new ArgumentException ("type is not a subclass of Multicastdelegate");
175
176                         return CreateDelegate_internal (type, target, method);
177
178                 }
179                 
180                 public static Delegate CreateDelegate (Type type, object target, string method)
181                 {
182                         return CreateDelegate(type, target, method, false);
183                 }
184
185                 public static Delegate CreateDelegate (Type type, Type target, string method)
186                 {
187                         if (type == null)
188                                 throw new ArgumentNullException ("type");
189
190                         if (target == null)
191                                 throw new ArgumentNullException ("target");
192
193                         if (method == null)
194                                 throw new ArgumentNullException ("method");
195
196                         if (!type.IsSubclassOf (typeof (MulticastDelegate)))
197                                 throw new ArgumentException ("type is not subclass of MulticastDelegate.");
198
199                         ParameterInfo[] delargs = type.GetMethod ("Invoke").GetParameters ();
200                         Type[] delargtypes = new Type [delargs.Length];
201
202                         for (int i=0; i<delargs.Length; i++)
203                                 delargtypes [i] = delargs [i].ParameterType;
204
205                         /* 
206                          * FIXME: we should check the caller has reflection permission
207                          * or if it lives in the same assembly...
208                          */
209                         BindingFlags flags = BindingFlags.ExactBinding | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic;
210                         MethodInfo info = target.GetMethod (method, flags, null, delargtypes, new ParameterModifier [0]);
211
212                         if (info == null)
213                                 throw new ArgumentException ("Couldn't bind to method.");
214
215                         return CreateDelegate_internal (type, null, info);
216                 }
217
218                 public static Delegate CreateDelegate (Type type, object target, string method, bool ignoreCase)
219                 {
220                         if (type == null)
221                                 throw new ArgumentNullException ("type");
222
223                         if (target == null)
224                                 throw new ArgumentNullException ("target");
225
226                         if (method == null)
227                                 throw new ArgumentNullException ("method");
228
229                         if (!type.IsSubclassOf (typeof (MulticastDelegate)))
230                                 throw new ArgumentException ("type");
231
232                         ParameterInfo[] delargs = type.GetMethod ("Invoke").GetParameters ();
233                         Type[] delargtypes = new Type [delargs.Length];
234
235                         for (int i=0; i<delargs.Length; i++)
236                                 delargtypes [i] = delargs [i].ParameterType;
237
238                         /* 
239                          * FIXME: we should check the caller has reflection permission
240                          * or if it lives in the same assembly...
241                          */
242                         BindingFlags flags = BindingFlags.ExactBinding | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
243
244                         if (ignoreCase)
245                                 flags |= BindingFlags.IgnoreCase;
246
247                         MethodInfo info = target.GetType ().GetMethod (method, flags, null, delargtypes, new ParameterModifier [0]);
248
249                         if (info == null)
250                                 throw new ArgumentException ("Couldn't bind to method '" + method + "'.");
251
252                         return CreateDelegate_internal (type, target, info);
253                 }
254
255                 public object DynamicInvoke (object[] args)
256                 {
257                         return DynamicInvokeImpl (args);
258                 }
259
260                 protected virtual object DynamicInvokeImpl (object[] args)
261                 {
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 ();
266                                 }
267                                 method_info = m_target.GetType ().GetMethod (method_name, mtypes);
268                         }
269
270 #if NET_2_0
271                         if ((m_target != null) && Method.IsStatic) {
272                                 // The delegate is bound to m_target
273                                 if (args != null) {
274                                         object[] newArgs = new object [args.Length + 1];
275                                         args.CopyTo (newArgs, 1);
276                                         newArgs [0] = m_target;
277                                         args = newArgs;
278                                 } else {
279                                         args = new object [] { m_target };
280                                 }
281                                 return Method.Invoke (null, args);
282                         }
283 #endif
284
285                         return Method.Invoke (m_target, args);
286                 }
287
288                 public virtual object Clone ()
289                 {
290                         return MemberwiseClone ();
291                 }
292
293                 public override bool Equals (object obj)
294                 {
295                         Delegate d = obj as Delegate;
296                         
297                         if (d == null)
298                                 return false;
299                         
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))
303                                 return true;
304
305                         return false;
306                 }
307
308                 public override int GetHashCode ()
309                 {
310                         // FIXME: Sync with Equals above
311                         return (int)method_ptr;
312                 }
313
314                 protected virtual MethodInfo GetMethodImpl ()
315                 {
316                         return Method;
317                 }
318
319                 // This is from ISerializable
320                 public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
321                 {
322                         DelegateSerializationHolder.GetDelegateData (this, info, context);
323                 }
324
325                 public virtual Delegate[] GetInvocationList()
326                 {
327                         return new Delegate[] { this };
328                 }
329
330                 /// <symmary>
331                 ///   Returns a new MulticastDelegate holding the
332                 ///   concatenated invocation lists of MulticastDelegates a and b
333                 /// </symmary>
334                 public static Delegate Combine (Delegate a, Delegate b)
335                 {
336                         if (a == null) {
337                                 if (b == null)
338                                         return null;
339                                 return b;
340                         } else 
341                                 if (b == null)
342                                         return a;
343
344                         if (a.GetType () != b.GetType ())
345                                 throw new ArgumentException (Locale.GetText ("Incompatible Delegate Types."));
346                         
347                         return a.CombineImpl (b);
348                 }
349
350                 /// <symmary>
351                 ///   Returns a new MulticastDelegate holding the
352                 ///   concatenated invocation lists of an Array of MulticastDelegates
353                 /// </symmary>
354                 public static Delegate Combine (Delegate[] delegates)
355                 {
356                         if (delegates == null)
357                                 return null;
358
359                         Delegate retval = null;
360
361                         foreach (Delegate next in delegates)
362                                 retval = Combine (retval, next);
363
364                         return retval;
365                 }
366
367                 protected virtual Delegate CombineImpl (Delegate d)
368                 {
369                         throw new MulticastNotSupportedException ("");
370                 }
371
372                 public static Delegate Remove (Delegate source, Delegate value) 
373                 {
374                         if (source == null)
375                                 return null;
376
377                         return source.RemoveImpl (value);
378                 }
379
380                 protected virtual Delegate RemoveImpl (Delegate d)
381                 {
382                         if (this.Equals (d))
383                                 return null;
384
385                         return this;
386                 }
387 #if NET_1_1
388                 public static Delegate RemoveAll (Delegate source, Delegate value)
389                 {
390                         Delegate tmp = source;
391                         while ((source = Delegate.Remove (source, value)) != tmp)
392                                 tmp = source;
393
394                         return tmp;
395                 }
396 #endif
397                 public static bool operator == (Delegate a, Delegate b)
398                 {
399                         if ((object)a == null) {
400                                 if ((object)b == null)
401                                         return true;
402                                 return false;
403                         } else if ((object) b == null)
404                                 return false;
405                         
406                         return a.Equals (b);
407                 }
408
409                 public static bool operator != (Delegate a, Delegate b)
410                 {
411                         return !(a == b);
412                 }
413         }
414 }