1 using System
.Reflection
;
2 using System
.Runtime
.CompilerServices
;
3 using System
.Runtime
.InteropServices
;
4 using System
.Runtime
.Serialization
;
8 /* Contains the rarely used fields of Delegate */
9 sealed class DelegateData
11 public Type target_type
;
12 public string method_name
;
13 public bool curried_first_arg
;
16 [StructLayout (LayoutKind
.Sequential
)]
17 partial class Delegate
19 #region Sync with object-internals.h
24 IntPtr delegate_trampoline
;
28 IntPtr interp_invoke_impl
;
29 MethodInfo method_info
;
31 // Keep a ref of the MethodInfo passed to CreateDelegate.
32 // Used to keep DynamicMethods alive.
33 MethodInfo original_method_info
;
37 bool method_is_virtual
;
40 protected Delegate (object target
, string method
)
43 throw new ArgumentNullException (nameof(target
));
46 throw new ArgumentNullException (nameof(method
));
48 this._target
= target
;
49 this.data
= new DelegateData () {
54 protected Delegate (Type target
, string method
)
57 throw new ArgumentNullException (nameof (target
));
59 if (target
.ContainsGenericParameters
)
60 throw new ArgumentException (SR
.Arg_UnboundGenParam
, nameof (target
));
63 throw new ArgumentNullException (nameof (method
));
65 if (!target
.IsRuntimeImplemented ())
66 throw new ArgumentException (SR
.Argument_MustBeRuntimeType
, nameof (target
));
68 this.data
= new DelegateData () {
74 public object Target
=> _target
;
76 public static Delegate
CreateDelegate (Type type
, object firstArgument
, MethodInfo method
, bool throwOnBindFailure
)
78 return CreateDelegate (type
, firstArgument
, method
, throwOnBindFailure
, true);
81 public static Delegate
CreateDelegate (Type type
, MethodInfo method
, bool throwOnBindFailure
)
83 return CreateDelegate (type
, null, method
, throwOnBindFailure
, false);
86 static Delegate
CreateDelegate (Type type
, object firstArgument
, MethodInfo method
, bool throwOnBindFailure
, bool allowClosed
)
89 throw new ArgumentNullException (nameof (type
));
91 throw new ArgumentNullException (nameof (method
));
93 RuntimeType rtType
= type
as RuntimeType
;
95 throw new ArgumentException (SR
.Argument_MustBeRuntimeType
, nameof (type
));
96 if (!(method
is RuntimeMethodInfo
|| method
is System
.Reflection
.Emit
.DynamicMethod
))
97 throw new ArgumentException (SR
.Argument_MustBeRuntimeMethodInfo
, nameof (method
));
99 if (!rtType
.IsDelegate ())
100 throw new ArgumentException (SR
.Arg_MustBeDelegate
, nameof (type
));
102 if (!IsMatchingCandidate (type
, firstArgument
, method
, allowClosed
, out DelegateData delegate_data
)) {
103 if (throwOnBindFailure
)
104 throw new ArgumentException (SR
.Arg_DlgtTargMeth
);
109 Delegate d
= CreateDelegate_internal (type
, firstArgument
, method
, throwOnBindFailure
);
111 d
.original_method_info
= method
;
112 if (delegate_data
!= null)
113 d
.data
= delegate_data
;
117 public static Delegate
CreateDelegate (Type type
, object target
, string method
, bool ignoreCase
, bool throwOnBindFailure
)
120 throw new ArgumentNullException (nameof (type
));
122 throw new ArgumentNullException (nameof (target
));
124 throw new ArgumentNullException (nameof (method
));
126 RuntimeType rtType
= type
as RuntimeType
;
128 throw new ArgumentException (SR
.Argument_MustBeRuntimeType
, nameof (type
));
129 if (!rtType
.IsDelegate ())
130 throw new ArgumentException (SR
.Arg_MustBeDelegate
, nameof (type
));
132 MethodInfo info
= GetCandidateMethod (type
, target
.GetType (), method
, BindingFlags
.Instance
, ignoreCase
);
134 if (throwOnBindFailure
)
135 throw new ArgumentException (SR
.Arg_DlgtTargMeth
);
140 return CreateDelegate_internal (type
, null, info
, throwOnBindFailure
);
143 public static Delegate
CreateDelegate (Type type
, Type target
, string method
, bool ignoreCase
, bool throwOnBindFailure
)
146 throw new ArgumentNullException (nameof (type
));
148 throw new ArgumentNullException (nameof (target
));
149 if (target
.ContainsGenericParameters
)
150 throw new ArgumentException (SR
.Arg_UnboundGenParam
, nameof (target
));
152 throw new ArgumentNullException (nameof (method
));
154 RuntimeType rtType
= type
as RuntimeType
;
155 RuntimeType rtTarget
= target
as RuntimeType
;
157 throw new ArgumentException (SR
.Argument_MustBeRuntimeType
, nameof (type
));
158 if (rtTarget
== null)
159 throw new ArgumentException (SR
.Argument_MustBeRuntimeType
, nameof (target
));
160 if (!rtType
.IsDelegate ())
161 throw new ArgumentException (SR
.Arg_MustBeDelegate
, nameof (type
));
163 MethodInfo info
= GetCandidateMethod (type
, target
, method
, BindingFlags
.Static
, ignoreCase
);
165 if (throwOnBindFailure
)
166 throw new ArgumentException (SR
.Arg_DlgtTargMeth
);
171 return CreateDelegate_internal (type
, null, info
, throwOnBindFailure
);
174 static MethodInfo
GetCandidateMethod (Type type
, Type target
, string method
, BindingFlags bflags
, bool ignoreCase
)
176 MethodInfo invoke
= type
.GetMethod ("Invoke");
177 ParameterInfo
[] delargs
= invoke
.GetParametersInternal ();
178 Type
[] delargtypes
= new Type
[delargs
.Length
];
180 for (int i
= 0; i
< delargs
.Length
; i
++)
181 delargtypes
[i
] = delargs
[i
].ParameterType
;
184 * since we need to walk the inheritance chain anyway to
185 * find private methods, adjust the bindingflags to ignore
188 BindingFlags flags
= BindingFlags
.ExactBinding
|
189 BindingFlags
.Public
| BindingFlags
.NonPublic
|
190 BindingFlags
.DeclaredOnly
| bflags
;
193 flags
|= BindingFlags
.IgnoreCase
;
195 MethodInfo info
= null;
197 for (Type targetType
= target
; targetType
!= null; targetType
= targetType
.BaseType
) {
198 MethodInfo mi
= targetType
.GetMethod (method
, flags
,
199 null, delargtypes
, Array
.Empty
<ParameterModifier
>());
200 if (mi
!= null && IsReturnTypeMatch (invoke
.ReturnType
, mi
.ReturnType
)) {
209 static bool IsMatchingCandidate (Type type
, object target
, MethodInfo method
, bool allowClosed
, out DelegateData delegate_data
)
211 MethodInfo invoke
= type
.GetMethod ("Invoke");
213 if (!IsReturnTypeMatch (invoke
.ReturnType
, method
.ReturnType
)) {
214 delegate_data
= null;
218 ParameterInfo
[] delargs
= invoke
.GetParametersInternal ();
219 ParameterInfo
[] args
= method
.GetParametersInternal ();
223 if (target
!= null) {
224 // delegate closed over target
225 if (!method
.IsStatic
)
226 // target is passed as this
227 argLengthMatch
= (args
.Length
== delargs
.Length
);
229 // target is passed as the first argument to the static method
230 argLengthMatch
= (args
.Length
== delargs
.Length
+ 1);
232 if (!method
.IsStatic
) {
234 // Net 2.0 feature. The first argument of the delegate is passed
235 // as the 'this' argument to the method.
237 argLengthMatch
= (args
.Length
+ 1 == delargs
.Length
);
240 // closed over a null reference
241 argLengthMatch
= (args
.Length
== delargs
.Length
);
243 argLengthMatch
= (args
.Length
== delargs
.Length
);
246 // closed over a null reference
247 argLengthMatch
= args
.Length
== delargs
.Length
+ 1;
251 if (!argLengthMatch
) {
252 delegate_data
= null;
257 delegate_data
= new DelegateData ();
259 if (target
!= null) {
260 if (!method
.IsStatic
) {
261 argsMatch
= IsArgumentTypeMatchWithThis (target
.GetType (), method
.DeclaringType
, true);
262 for (int i
= 0; i
< args
.Length
; i
++)
263 argsMatch
&= IsArgumentTypeMatch (delargs
[i
].ParameterType
, args
[i
].ParameterType
);
265 argsMatch
= IsArgumentTypeMatch (target
.GetType (), args
[0].ParameterType
);
266 for (int i
= 1; i
< args
.Length
; i
++)
267 argsMatch
&= IsArgumentTypeMatch (delargs
[i
- 1].ParameterType
, args
[i
].ParameterType
);
269 delegate_data
.curried_first_arg
= true;
272 if (!method
.IsStatic
) {
273 if (args
.Length
+ 1 == delargs
.Length
) {
274 // The first argument should match this
275 argsMatch
= IsArgumentTypeMatchWithThis (delargs
[0].ParameterType
, method
.DeclaringType
, false);
276 for (int i
= 0; i
< args
.Length
; i
++)
277 argsMatch
&= IsArgumentTypeMatch (delargs
[i
+ 1].ParameterType
, args
[i
].ParameterType
);
279 // closed over a null reference
280 argsMatch
= allowClosed
;
281 for (int i
= 0; i
< args
.Length
; i
++)
282 argsMatch
&= IsArgumentTypeMatch (delargs
[i
].ParameterType
, args
[i
].ParameterType
);
285 if (delargs
.Length
+ 1 == args
.Length
) {
286 // closed over a null reference
287 argsMatch
= !(args
[0].ParameterType
.IsValueType
|| args
[0].ParameterType
.IsByRef
) && allowClosed
;
288 for (int i
= 0; i
< delargs
.Length
; i
++)
289 argsMatch
&= IsArgumentTypeMatch (delargs
[i
].ParameterType
, args
[i
+ 1].ParameterType
);
291 delegate_data
.curried_first_arg
= true;
294 for (int i
= 0; i
< args
.Length
; i
++)
295 argsMatch
&= IsArgumentTypeMatch (delargs
[i
].ParameterType
, args
[i
].ParameterType
);
303 static bool IsReturnTypeMatch (Type delReturnType
, Type returnType
)
305 bool returnMatch
= returnType
== delReturnType
;
308 // Delegate covariance
309 if (!returnType
.IsValueType
&& delReturnType
.IsAssignableFrom (returnType
))
316 static bool IsArgumentTypeMatch (Type delArgType
, Type argType
)
318 bool match
= delArgType
== argType
;
320 // Delegate contravariance
322 if (!argType
.IsValueType
&& argType
.IsAssignableFrom (delArgType
))
327 if (delArgType
.IsEnum
&& Enum
.GetUnderlyingType (delArgType
) == argType
)
329 else if (argType
.IsEnum
&& Enum
.GetUnderlyingType (argType
) == delArgType
)
336 static bool IsArgumentTypeMatchWithThis (Type delArgType
, Type argType
, bool boxedThis
)
339 if (argType
.IsValueType
)
340 match
= delArgType
.IsByRef
&& delArgType
.GetElementType () == argType
||
341 (boxedThis
&& delArgType
== argType
);
343 match
= delArgType
== argType
|| argType
.IsAssignableFrom (delArgType
);
348 protected virtual object DynamicInvokeImpl (object[] args
)
350 if (Method
== null) {
351 Type
[] mtypes
= new Type
[args
.Length
];
352 for (int i
= 0; i
< args
.Length
; ++i
) {
353 mtypes
[i
] = args
[i
].GetType ();
355 method_info
= _target
.GetType ().GetMethod (data
.method_name
, mtypes
);
358 var target
= _target
;
359 if (this.data
== null)
360 InitializeDelegateData ();
362 if (Method
.IsStatic
) {
364 // The delegate is bound to _target
366 if (data
.curried_first_arg
) {
368 args
= new [] { target }
;
370 Array
.Resize (ref args
, args
.Length
+ 1);
371 Array
.Copy (args
, 0, args
, 1, args
.Length
- 1);
378 if (_target
== null && args
!= null && args
.Length
> 0) {
380 Array
.Copy (args
, 1, args
, 0, args
.Length
- 1);
381 Array
.Resize (ref args
, args
.Length
- 1);
385 return Method
.Invoke (target
, args
);
388 public override bool Equals (object obj
)
390 Delegate d
= obj
as Delegate
;
395 // Do not compare method_ptr, since it can point to a trampoline
396 if (d
._target
== _target
&& d
.Method
== Method
) {
397 if (d
.data
!= null || data
!= null) {
399 if (d
.data
!= null && data
!= null)
400 return (d
.data
.target_type
== data
.target_type
&& d
.data
.method_name
== data
.method_name
);
403 return d
.data
.target_type
== null;
405 return data
.target_type
== null;
415 public override int GetHashCode ()
417 MethodInfo m
= Method
;
419 return (m
!= null ? m
.GetHashCode () : GetType ().GetHashCode ()) ^ RuntimeHelpers
.GetHashCode (_target
);
422 protected virtual MethodInfo
GetMethodImpl ()
424 if (method_info
!= null)
427 if (method
!= IntPtr
.Zero
) {
428 if (!method_is_virtual
)
429 method_info
= (MethodInfo
) RuntimeMethodInfo
.GetMethodFromHandleNoGenericCheck (new RuntimeMethodHandle (method
));
431 method_info
= GetVirtualMethod_internal ();
437 void InitializeDelegateData ()
439 DelegateData delegate_data
= new DelegateData ();
440 if (method_info
.IsStatic
) {
441 if (_target
!= null) {
442 delegate_data
.curried_first_arg
= true;
444 MethodInfo invoke
= GetType ().GetMethod ("Invoke");
445 if (invoke
.GetParametersCount () + 1 == method_info
.GetParametersCount ())
446 delegate_data
.curried_first_arg
= true;
449 this.data
= delegate_data
;
452 static bool InternalEqualTypes (object source
, object value)
454 return source
.GetType () == value.GetType ();
457 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
458 private protected extern static MulticastDelegate
AllocDelegateLike_internal (Delegate d
);
460 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
461 static extern Delegate
CreateDelegate_internal (Type type
, object target
, MethodInfo info
, bool throwOnBindFailure
);
463 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
464 extern MethodInfo
GetVirtualMethod_internal ();