CSLA.NET 5.4.2
CSLA .NET is a software development framework that helps you build a reusable, maintainable object-oriented business layer for your app.
MethodCaller.cs
Go to the documentation of this file.
1//-----------------------------------------------------------------------
2// <copyright file="MethodCaller.cs" company="Marimer LLC">
3// Copyright (c) Marimer LLC. All rights reserved.
4// Website: https://cslanet.com
5// </copyright>
6// <summary>Provides methods to dynamically find and call methods.</summary>
7//-----------------------------------------------------------------------
8using System;
9using System.Collections.Generic;
10using System.ComponentModel;
11using System.Reflection;
12using Csla.Properties;
13using System.Globalization;
14using System.Threading.Tasks;
15using Microsoft.Extensions.DependencyInjection;
16using System.Runtime.Loader;
17
18namespace Csla.Reflection
19{
23 public static class MethodCaller
24 {
25 private const BindingFlags allLevelFlags
26 = BindingFlags.FlattenHierarchy
27 | BindingFlags.Instance
28 | BindingFlags.Public
29 | BindingFlags.NonPublic
30 ;
31
32 private const BindingFlags oneLevelFlags
33 = BindingFlags.DeclaredOnly
34 | BindingFlags.Instance
35 | BindingFlags.Public
36 | BindingFlags.NonPublic
37 ;
38
39 private const BindingFlags ctorFlags
40 = BindingFlags.Instance
41 | BindingFlags.Public
42 | BindingFlags.NonPublic
43 ;
44
45 private const BindingFlags factoryFlags =
46 BindingFlags.Static |
47 BindingFlags.Public |
48 BindingFlags.FlattenHierarchy;
49
50 private const BindingFlags privateMethodFlags =
51 BindingFlags.Public |
52 BindingFlags.NonPublic |
53 BindingFlags.Instance |
54 BindingFlags.FlattenHierarchy;
55
56 #region Dynamic Method Cache
57
58 private readonly static Dictionary<MethodCacheKey, DynamicMethodHandle> _methodCache = new Dictionary<MethodCacheKey, DynamicMethodHandle>();
59
60 private static DynamicMethodHandle GetCachedMethod(object obj, System.Reflection.MethodInfo info, params object[] parameters)
61 {
62 var key = new MethodCacheKey(obj.GetType().FullName, info.Name, GetParameterTypes(parameters));
63 DynamicMethodHandle mh = null;
64 var found = false;
65 try
66 {
67 found = _methodCache.TryGetValue(key, out mh);
68 }
69 catch
70 { /* failure will drop into !found block */ }
71 if (!found)
72 {
73 lock (_methodCache)
74 {
75 if (!_methodCache.TryGetValue(key, out mh))
76 {
77 mh = new DynamicMethodHandle(info, parameters);
78 _methodCache.Add(key, mh);
79 }
80 }
81 }
82 return mh;
83 }
84
85 private static DynamicMethodHandle GetCachedMethod(object obj, string method, params object[] parameters)
86 {
87 return GetCachedMethod(obj, method, true, parameters);
88 }
89
90 private static DynamicMethodHandle GetCachedMethod(object obj, string method, bool hasParameters, params object[] parameters)
91 {
92 var key = new MethodCacheKey(obj.GetType().FullName, method, GetParameterTypes(hasParameters, parameters));
93 if (!_methodCache.TryGetValue(key, out DynamicMethodHandle mh))
94 {
95 lock (_methodCache)
96 {
97 if (!_methodCache.TryGetValue(key, out mh))
98 {
99 var info = GetMethod(obj.GetType(), method, hasParameters, parameters);
100 mh = new DynamicMethodHandle(info, parameters);
101 _methodCache.Add(key, mh);
102 }
103 }
104 }
105 return mh;
106 }
107
108 #endregion
109
110 #region Dynamic Constructor Cache
111
112 private readonly static Dictionary<Type, DynamicCtorDelegate> _ctorCache = new Dictionary<Type, DynamicCtorDelegate>();
113
114 private static DynamicCtorDelegate GetCachedConstructor(Type objectType)
115 {
116 if (objectType == null)
117 throw new ArgumentNullException(nameof(objectType));
118
119 DynamicCtorDelegate result = null;
120 var found = false;
121 try
122 {
123 found = _ctorCache.TryGetValue(objectType, out result);
124 }
125 catch
126 { /* failure will drop into !found block */ }
127 if (!found)
128 {
129 lock (_ctorCache)
130 {
131 if (!_ctorCache.TryGetValue(objectType, out result))
132 {
133 ConstructorInfo info = objectType.GetConstructor(ctorFlags, null, Type.EmptyTypes, null);
134 if (info == null)
135 throw new NotSupportedException(string.Format(
136 CultureInfo.CurrentCulture,
137 "Cannot create instance of Type '{0}'. No public parameterless constructor found.",
138 objectType));
139
140 result = DynamicMethodHandlerFactory.CreateConstructor(info);
141 _ctorCache.Add(objectType, result);
142 }
143 }
144 }
145 return result;
146 }
147
148 #endregion
149
150 #region GetType
151
158 public static Type GetType(string typeName, bool throwOnError, bool ignoreCase)
159 {
160 try
161 {
162 return Type.GetType(typeName, throwOnError, ignoreCase);
163 }
164 catch
165 {
166 string[] splitName = typeName.Split(',');
167 if (splitName.Length > 2)
168 {
169 var asm = AssemblyLoadContext.Default.LoadFromAssemblyPath(AppContext.BaseDirectory + splitName[1].Trim() + ".dll");
170 return asm.GetType(splitName[0].Trim());
171 }
172 else
173 {
174 throw;
175 }
176 }
177 }
178
184 public static Type GetType(string typeName, bool throwOnError)
185 {
186 return GetType(typeName, throwOnError, false);
187 }
188
193 public static Type GetType(string typeName)
194 {
195 return GetType(typeName, true, false);
196 }
197
198 #endregion
199
200 #region Create Instance
201
207 public static object CreateInstance(Type objectType)
208 {
209 var provider = ApplicationContext.CurrentServiceProvider;
210 if (provider is null)
211 provider = ApplicationContext.DefaultServiceProvider;
212 if (provider != null)
213 return ActivatorUtilities.CreateInstance(provider, objectType);
214 else
215 return Activator.CreateInstance(objectType);
216 }
217
223 public static object CreateInstance(Type objectType, params object[] parameters)
224 {
225 var provider = ApplicationContext.CurrentServiceProvider;
226 if (provider is null)
227 provider = ApplicationContext.DefaultServiceProvider;
228 if (provider != null)
229 return ActivatorUtilities.CreateInstance(provider, objectType, parameters);
230 else
231 return Activator.CreateInstance(objectType, parameters);
232 }
233
241 public static object CreateGenericInstance(Type type, params Type[] paramTypes)
242 {
243 var genericType = type.GetGenericTypeDefinition();
244 var gt = genericType.MakeGenericType(paramTypes);
245 return CreateInstance(gt);
246 }
247
248 #endregion
249
250 private const BindingFlags propertyFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
251 private const BindingFlags fieldFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
252
253 private static readonly Dictionary<MethodCacheKey, DynamicMemberHandle> _memberCache = new Dictionary<MethodCacheKey, DynamicMemberHandle>();
254
255 internal static DynamicMemberHandle GetCachedProperty(Type objectType, string propertyName)
256 {
257 var key = new MethodCacheKey(objectType.FullName, propertyName, GetParameterTypes(null));
258 if (!_memberCache.TryGetValue(key, out DynamicMemberHandle mh))
259 {
260 lock (_memberCache)
261 {
262 if (!_memberCache.TryGetValue(key, out mh))
263 {
264 PropertyInfo info = objectType.GetProperty(propertyName, propertyFlags);
265 if (info == null)
266 throw new InvalidOperationException(
267 string.Format(Resources.MemberNotFoundException, propertyName));
268 mh = new DynamicMemberHandle(info);
269 _memberCache.Add(key, mh);
270 }
271 }
272 }
273 return mh;
274 }
275
276 internal static DynamicMemberHandle GetCachedField(Type objectType, string fieldName)
277 {
278 var key = new MethodCacheKey(objectType.FullName, fieldName, GetParameterTypes(null));
279 if (!_memberCache.TryGetValue(key, out DynamicMemberHandle mh))
280 {
281 lock (_memberCache)
282 {
283 if (!_memberCache.TryGetValue(key, out mh))
284 {
285 FieldInfo info = objectType.GetField(fieldName, fieldFlags);
286 if (info == null)
287 throw new InvalidOperationException(
288 string.Format(Resources.MemberNotFoundException, fieldName));
289 mh = new DynamicMemberHandle(info);
290 _memberCache.Add(key, mh);
291 }
292 }
293 }
294 return mh;
295 }
296
304 public static object CallPropertyGetter(object obj, string property)
305 {
306 if (ApplicationContext.UseReflectionFallback)
307 {
308 var propertyInfo = obj.GetType().GetProperty(property);
309 return propertyInfo.GetValue(obj);
310 }
311 else
312 {
313 if (obj == null)
314 throw new ArgumentNullException("obj");
315 if (string.IsNullOrEmpty(property))
316 throw new ArgumentException("Argument is null or empty.", "property");
317
318 var mh = GetCachedProperty(obj.GetType(), property);
319 if (mh.DynamicMemberGet == null)
320 {
321 throw new NotSupportedException(string.Format(
322 CultureInfo.CurrentCulture,
323 "The property '{0}' on Type '{1}' does not have a public getter.",
324 property,
325 obj.GetType()));
326 }
327
328 return mh.DynamicMemberGet(obj);
329 }
330 }
331
339 public static void CallPropertySetter(object obj, string property, object value)
340 {
341 if (obj == null)
342 throw new ArgumentNullException("obj");
343 if (string.IsNullOrEmpty(property))
344 throw new ArgumentException("Argument is null or empty.", "property");
345
346 if (ApplicationContext.UseReflectionFallback)
347 {
348 var propertyInfo = obj.GetType().GetProperty(property);
349 propertyInfo.SetValue(obj, value);
350 }
351 else
352 {
353 var mh = GetCachedProperty(obj.GetType(), property);
354 if (mh.DynamicMemberSet == null)
355 {
356 throw new NotSupportedException(string.Format(
357 CultureInfo.CurrentCulture,
358 "The property '{0}' on Type '{1}' does not have a public setter.",
359 property,
360 obj.GetType()));
361 }
362
363 mh.DynamicMemberSet(obj, value);
364 }
365 }
366
367
368 #region Call Method
369
380 public static object CallMethodIfImplemented(object obj, string method)
381 {
382 return CallMethodIfImplemented(obj, method, false, null);
383 }
384
398 public static object CallMethodIfImplemented(object obj, string method, params object[] parameters)
399 {
400 return CallMethodIfImplemented(obj, method, true, parameters);
401 }
402
403 private static object CallMethodIfImplemented(object obj, string method, bool hasParameters, params object[] parameters)
404 {
405 if (ApplicationContext.UseReflectionFallback)
406 {
407 var found = (FindMethod(obj.GetType(), method, GetParameterTypes(hasParameters, parameters)) != null);
408 if (found)
409 return CallMethod(obj, method, parameters);
410 else
411 return null;
412 }
413 else
414 {
415 var mh = GetCachedMethod(obj, method, parameters);
416 if (mh == null || mh.DynamicMethod == null)
417 return null;
418 return CallMethod(obj, mh, hasParameters, parameters);
419 }
420 }
421
429 public static bool IsMethodImplemented(object obj, string method, params object[] parameters)
430 {
431 var mh = GetCachedMethod(obj, method, parameters);
432 return mh != null && mh.DynamicMethod != null;
433 }
434
446 public static object CallMethod(object obj, string method)
447 {
448 return CallMethod(obj, method, false, null);
449 }
450
465 public static object CallMethod(object obj, string method, params object[] parameters)
466 {
467 return CallMethod(obj, method, true, parameters);
468 }
469
470 private static object CallMethod(object obj, string method, bool hasParameters, params object[] parameters)
471 {
472 if (ApplicationContext.UseReflectionFallback)
473 {
474 System.Reflection.MethodInfo info = GetMethod(obj.GetType(), method, hasParameters, parameters);
475 if (info == null)
476 throw new NotImplementedException(obj.GetType().Name + "." + method + " " + Resources.MethodNotImplemented);
477
478 return CallMethod(obj, info, hasParameters, parameters);
479 }
480 else
481 {
482 var mh = GetCachedMethod(obj, method, hasParameters, parameters);
483 if (mh == null || mh.DynamicMethod == null)
484 throw new NotImplementedException(obj.GetType().Name + "." + method + " " + Resources.MethodNotImplemented);
485 return CallMethod(obj, mh, hasParameters, parameters);
486 }
487 }
488
503 public static object CallMethod(object obj, System.Reflection.MethodInfo info, params object[] parameters)
504 {
505 return CallMethod(obj, info, true, parameters);
506 }
507
508 private static object CallMethod(object obj, System.Reflection.MethodInfo info, bool hasParameters, params object[] parameters)
509 {
510 if (ApplicationContext.UseReflectionFallback)
511 {
512 var infoParams = info.GetParameters();
513 var infoParamsCount = infoParams.Length;
514 bool hasParamArray = infoParamsCount > 0 && infoParams[infoParamsCount - 1].GetCustomAttributes(typeof(ParamArrayAttribute), true).Length > 0;
515 bool specialParamArray = false;
516 if (hasParamArray && infoParams[infoParamsCount - 1].ParameterType.Equals(typeof(string[])))
517 specialParamArray = true;
518 if (hasParamArray && infoParams[infoParamsCount - 1].ParameterType.Equals(typeof(object[])))
519 specialParamArray = true;
520 object[] par;
521 if (infoParamsCount == 1 && specialParamArray)
522 {
523 par = new object[] { parameters };
524 }
525 else if (infoParamsCount > 1 && hasParamArray && specialParamArray)
526 {
527 par = new object[infoParamsCount];
528 for (int i = 0; i < infoParamsCount - 1; i++)
529 par[i] = parameters[i];
530 par[infoParamsCount - 1] = parameters[infoParamsCount - 1];
531 }
532 else
533 {
534 par = parameters;
535 }
536
537 object result;
538 try
539 {
540 result = info.Invoke(obj, par);
541 }
542 catch (Exception e)
543 {
544 Exception inner;
545 if (e.InnerException == null)
546 inner = e;
547 else
548 inner = e.InnerException;
549 throw new CallMethodException(obj.GetType().Name + "." + info.Name + " " + Resources.MethodCallFailed, inner);
550 }
551 return result;
552 }
553 else
554 {
555 var mh = GetCachedMethod(obj, info, parameters);
556 if (mh == null || mh.DynamicMethod == null)
557 throw new NotImplementedException(obj.GetType().Name + "." + info.Name + " " + Resources.MethodNotImplemented);
558 return CallMethod(obj, mh, hasParameters, parameters);
559 }
560 }
561
562 private static object CallMethod(object obj, DynamicMethodHandle methodHandle, bool hasParameters, params object[] parameters)
563 {
564 object result = null;
565 var method = methodHandle.DynamicMethod;
566
567 object[] inParams;
568 if (parameters == null)
569 inParams = new object[] { null };
570 else
571 inParams = parameters;
572
573 if (methodHandle.HasFinalArrayParam)
574 {
575 // last param is a param array or only param is an array
576 var pCount = methodHandle.MethodParamsLength;
577 var inCount = inParams.Length;
578 if (inCount == pCount - 1)
579 {
580 // no paramter was supplied for the param array
581 // copy items into new array with last entry null
582 object[] paramList = new object[pCount];
583 for (var pos = 0; pos <= pCount - 2; pos++)
584 paramList[pos] = parameters[pos];
585 paramList[paramList.Length - 1] = hasParameters && inParams.Length == 0 ? inParams : null;
586
587 // use new array
588 inParams = paramList;
589 }
590 else if ((inCount == pCount && inParams[inCount - 1] != null && !inParams[inCount - 1].GetType().IsArray) || inCount > pCount)
591 {
592 // 1 or more params go in the param array
593 // copy extras into an array
594 var extras = inParams.Length - (pCount - 1);
595 object[] extraArray = GetExtrasArray(extras, methodHandle.FinalArrayElementType);
596 Array.Copy(inParams, pCount - 1, extraArray, 0, extras);
597
598 // copy items into new array
599 object[] paramList = new object[pCount];
600 for (var pos = 0; pos <= pCount - 2; pos++)
601 paramList[pos] = parameters[pos];
602 paramList[paramList.Length - 1] = extraArray;
603
604 // use new array
605 inParams = paramList;
606 }
607 }
608 try
609 {
610 result = methodHandle.DynamicMethod(obj, inParams);
611 }
612 catch (Exception ex)
613 {
614 throw new CallMethodException(obj.GetType().Name + "." + methodHandle.MethodName + " " + Resources.MethodCallFailed, ex);
615 }
616 return result;
617 }
618
619 private static object[] GetExtrasArray(int count, Type arrayType)
620 {
621 return (object[])(System.Array.CreateInstance(arrayType.GetElementType(), count));
622 }
623#endregion
624
625#region Get/Find Method
626
637 public static System.Reflection.MethodInfo GetMethod(Type objectType, string method)
638 {
639 return GetMethod(objectType, method, true, false, null);
640 }
641
655 public static System.Reflection.MethodInfo GetMethod(Type objectType, string method, params object[] parameters)
656 {
657 return GetMethod(objectType, method, true, parameters);
658 }
659
660 private static System.Reflection.MethodInfo GetMethod(Type objectType, string method, bool hasParameters, params object[] parameters)
661 {
662 System.Reflection.MethodInfo result;
663
664 object[] inParams;
665 if (!hasParameters)
666 inParams = new object[] { };
667 else if (parameters == null)
668 inParams = new object[] { null };
669 else
670 inParams = parameters;
671
672 // try to find a strongly typed match
673
674 // first see if there's a matching method
675 // where all params match types
676 result = FindMethod(objectType, method, GetParameterTypes(hasParameters, inParams));
677
678 if (result == null)
679 {
680 // no match found - so look for any method
681 // with the right number of parameters
682 try
683 {
684 result = FindMethod(objectType, method, inParams.Length);
685 }
686 catch (AmbiguousMatchException)
687 {
688 // we have multiple methods matching by name and parameter count
689 result = FindMethodUsingFuzzyMatching(objectType, method, inParams);
690 }
691 }
692
693 // no strongly typed match found, get default based on name only
694 if (result == null)
695 {
696 result = objectType.GetMethod(method, allLevelFlags);
697 }
698 return result;
699 }
700
701 private static System.Reflection.MethodInfo FindMethodUsingFuzzyMatching(Type objectType, string method, object[] parameters)
702 {
703 System.Reflection.MethodInfo result = null;
704 Type currentType = objectType;
705 do
706 {
707 System.Reflection.MethodInfo[] methods = currentType.GetMethods(oneLevelFlags);
708 int parameterCount = parameters.Length;
709 // Match based on name and parameter types and parameter arrays
710 foreach (System.Reflection.MethodInfo m in methods)
711 {
712 if (m.Name == method)
713 {
714 var infoParams = m.GetParameters();
715 var pCount = infoParams.Length;
716 if (pCount > 0)
717 {
718 if (pCount == 1 && infoParams[0].ParameterType.IsArray)
719 {
720 // only param is an array
721 if (parameters.GetType().Equals(infoParams[0].ParameterType))
722 {
723 // got a match so use it
724 result = m;
725 break;
726 }
727 }
728 if (infoParams[pCount - 1].GetCustomAttributes(typeof(ParamArrayAttribute), true).Length > 0)
729 {
730 // last param is a param array
731 if (parameterCount == pCount && parameters[pCount - 1].GetType().Equals(infoParams[pCount - 1].ParameterType))
732 {
733 // got a match so use it
734 result = m;
735 break;
736 }
737 }
738 }
739 }
740 }
741 if (result == null)
742 {
743 // match based on parameter name and number of parameters
744 foreach (System.Reflection.MethodInfo m in methods)
745 {
746 if (m.Name == method && m.GetParameters().Length == parameterCount)
747 {
748 result = m;
749 break;
750 }
751 }
752 }
753 if (result != null)
754 break;
755 currentType = currentType.BaseType;
756 } while (currentType != null);
757
758
759 return result;
760 }
761
777 public static System.Reflection.MethodInfo FindMethod(Type objectType, string method, Type[] types)
778 {
779 System.Reflection.MethodInfo info;
780 do
781 {
782 // find for a strongly typed match
783 info = objectType.GetMethod(method, oneLevelFlags, null, types, null);
784 if (info != null)
785 {
786 break; // match found
787 }
788
789 objectType = objectType.BaseType;
790 } while (objectType != null);
791
792 return info;
793 }
794
809 public static System.Reflection.MethodInfo FindMethod(Type objectType, string method, int parameterCount)
810 {
811 // walk up the inheritance hierarchy looking
812 // for a method with the right number of
813 // parameters
814 System.Reflection.MethodInfo result = null;
815 Type currentType = objectType;
816 do
817 {
818 System.Reflection.MethodInfo info = currentType.GetMethod(method, oneLevelFlags);
819 if (info != null)
820 {
821 var infoParams = info.GetParameters();
822 var pCount = infoParams.Length;
823 if (pCount > 0 &&
824 ((pCount == 1 && infoParams[0].ParameterType.IsArray) ||
825 (infoParams[pCount - 1].GetCustomAttributes(typeof(ParamArrayAttribute), true).Length > 0)))
826 {
827 // last param is a param array or only param is an array
828 if (parameterCount >= pCount - 1)
829 {
830 // got a match so use it
831 result = info;
832 break;
833 }
834 }
835 else if (pCount == parameterCount)
836 {
837 // got a match so use it
838 result = info;
839 break;
840 }
841 }
842 currentType = currentType.BaseType;
843 } while (currentType != null);
844
845 return result;
846 }
847
848#endregion
849
854 public static Type[] GetParameterTypes()
855 {
856 return GetParameterTypes(false, null);
857 }
858
866 public static Type[] GetParameterTypes(object[] parameters)
867 {
868 return GetParameterTypes(true, parameters);
869 }
870
871 private static Type[] GetParameterTypes(bool hasParameters, object[] parameters)
872 {
873 if (!hasParameters)
874 return new Type[] { };
875
876 List<Type> result = new List<Type>();
877
878 if (parameters == null)
879 {
880 result.Add(typeof(object));
881
882 }
883 else
884 {
885 foreach (object item in parameters)
886 {
887 if (item == null)
888 {
889 result.Add(typeof(object));
890 }
891 else
892 {
893 result.Add(item.GetType());
894 }
895 }
896 }
897 return result.ToArray();
898 }
899
905 public static PropertyDescriptor GetPropertyDescriptor(Type t, string propertyName)
906 {
907 var propertyDescriptors = TypeDescriptor.GetProperties(t);
908 PropertyDescriptor result = null;
909 foreach (PropertyDescriptor desc in propertyDescriptors)
910 if (desc.Name == propertyName)
911 {
912 result = desc;
913 break;
914 }
915 return result;
916 }
917
923 public static PropertyInfo GetProperty(Type objectType, string propertyName)
924 {
925 return objectType.GetProperty(propertyName, propertyFlags);
926 }
927
934 public static object GetPropertyValue(object obj, PropertyInfo info)
935 {
936 object result;
937 try
938 {
939 result = info.GetValue(obj, null);
940 }
941 catch (Exception e)
942 {
943 Exception inner;
944 if (e.InnerException == null)
945 inner = e;
946 else
947 inner = e.InnerException;
948 throw new CallMethodException(obj.GetType().Name + "." + info.Name + " " + Resources.MethodCallFailed, inner);
949 }
950 return result;
951 }
952
959 public static object CallMethod(object obj, System.Reflection.MethodInfo info)
960 {
961 object result;
962 try
963 {
964 result = info.Invoke(obj, null);
965 }
966 catch (Exception e)
967 {
968 Exception inner;
969 if (e.InnerException == null)
970 inner = e;
971 else
972 inner = e.InnerException;
973 throw new CallMethodException(obj.GetType().Name + "." + info.Name + " " + Resources.MethodCallFailed, inner);
974 }
975 return result;
976 }
977
992 public async static Task<object> CallMethodTryAsync(object obj, string method, params object[] parameters)
993 {
994 return await CallMethodTryAsync(obj, method, true, parameters);
995 }
996
1005 public async static Task<object> CallMethodTryAsync(object obj, string method)
1006 {
1007 return await CallMethodTryAsync(obj, method, false, null);
1008 }
1009
1010 private async static Task<object> CallMethodTryAsync(object obj, string method, bool hasParameters, params object[] parameters)
1011 {
1012 try
1013 {
1014 if (ApplicationContext.UseReflectionFallback)
1015 {
1016 var info = FindMethod(obj.GetType(), method, GetParameterTypes(hasParameters, parameters));
1017 if (info == null)
1018 throw new NotImplementedException(obj.GetType().Name + "." + method + " " + Resources.MethodNotImplemented);
1019 var isAsyncTask = (info.ReturnType == typeof(Task));
1020 var isAsyncTaskObject = (info.ReturnType.IsGenericType && (info.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)));
1021 if (isAsyncTask)
1022 {
1023 await (Task)CallMethod(obj, method, hasParameters, parameters);
1024 return null;
1025 }
1026 else if (isAsyncTaskObject)
1027 {
1028 return await (Task<object>)CallMethod(obj, method, hasParameters, parameters);
1029 }
1030 else
1031 {
1032 return CallMethod(obj, method, hasParameters, parameters);
1033 }
1034 }
1035 else
1036 {
1037 var mh = GetCachedMethod(obj, method, hasParameters, parameters);
1038 if (mh == null || mh.DynamicMethod == null)
1039 throw new NotImplementedException(obj.GetType().Name + "." + method + " " + Resources.MethodNotImplemented);
1040 if (mh.IsAsyncTask)
1041 {
1042 await (Task)CallMethod(obj, mh, hasParameters, parameters);
1043 return null;
1044 }
1045 else if (mh.IsAsyncTaskObject)
1046 {
1047 return await (Task<object>)CallMethod(obj, mh, hasParameters, parameters);
1048 }
1049 else
1050 {
1051 return CallMethod(obj, mh, hasParameters, parameters);
1052 }
1053 }
1054 }
1055 catch (InvalidCastException ex)
1056 {
1057 throw new NotSupportedException(
1058 string.Format(Resources.TaskOfObjectException, obj.GetType().Name + "." + method),
1059 ex);
1060 }
1061 }
1062
1068 public static bool IsAsyncMethod(object obj, string method)
1069 {
1070 return IsAsyncMethod(obj, method, false, null);
1071 }
1072
1081 public static bool IsAsyncMethod(object obj, string method, params object[] parameters)
1082 {
1083 return IsAsyncMethod(obj, method, true, parameters);
1084 }
1085
1086 internal static bool IsAsyncMethod(System.Reflection.MethodInfo info)
1087 {
1088 var isAsyncTask = (info.ReturnType == typeof(Task));
1089 var isAsyncTaskObject = (info.ReturnType.IsGenericType && (info.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)));
1090 return isAsyncTask || isAsyncTaskObject;
1091 }
1092
1093 private static bool IsAsyncMethod(object obj, string method, bool hasParameters, params object[] parameters)
1094 {
1095 if (ApplicationContext.UseReflectionFallback)
1096 {
1097 var info = FindMethod(obj.GetType(), method, GetParameterTypes(hasParameters, parameters));
1098 if (info == null)
1099 throw new NotImplementedException(obj.GetType().Name + "." + method + " " + Resources.MethodNotImplemented);
1100 return IsAsyncMethod(info);
1101 }
1102 else
1103 {
1104 var mh = GetCachedMethod(obj, method, hasParameters, parameters);
1105 if (mh == null || mh.DynamicMethod == null)
1106 throw new NotImplementedException(obj.GetType().Name + "." + method + " " + Resources.MethodNotImplemented);
1107
1108 return mh.IsAsyncTask || mh.IsAsyncTaskObject;
1109 }
1110 }
1111
1121 public static Task<object> CallGenericStaticMethodAsync(Type objectType, string method, Type[] typeParams, bool hasParameters, params object[] parameters)
1122 {
1123 var tcs = new TaskCompletionSource<object>();
1124 try
1125 {
1126 Task task = null;
1127 if (hasParameters)
1128 {
1129 var pTypes = GetParameterTypes(parameters);
1130 var methodReference = objectType.GetMethod(method, BindingFlags.Static | BindingFlags.Public, null, CallingConventions.Any, pTypes, null);
1131 if (methodReference == null)
1132 methodReference = objectType.GetMethod(method, BindingFlags.Static | BindingFlags.Public);
1133 if (methodReference == null)
1134 throw new InvalidOperationException(objectType.Name + "." + method);
1135 var gr = methodReference.MakeGenericMethod(typeParams);
1136 task = (Task)gr.Invoke(null, parameters);
1137 }
1138 else
1139 {
1140 var methodReference = objectType.GetMethod(method, BindingFlags.Static | BindingFlags.Public, null, CallingConventions.Any, System.Type.EmptyTypes, null);
1141 var gr = methodReference.MakeGenericMethod(typeParams);
1142 task = (Task)gr.Invoke(null, null);
1143 }
1144 task.Wait();
1145 if (task.Exception != null)
1146 tcs.SetException(task.Exception);
1147 else
1148 tcs.SetResult(Csla.Reflection.MethodCaller.CallPropertyGetter(task, "Result"));
1149 }
1150 catch (Exception ex)
1151 {
1152 tcs.SetException(ex);
1153 }
1154 return tcs.Task;
1155 }
1156
1166 public static object CallGenericMethod(object target, string method, Type[] typeParams, bool hasParameters, params object[] parameters)
1167 {
1168 var objectType = target.GetType();
1169 object result;
1170 if (hasParameters)
1171 {
1172 var pTypes = GetParameterTypes(parameters);
1173 var methodReference = objectType.GetMethod(method, BindingFlags.Instance | BindingFlags.Public, null, CallingConventions.Any, pTypes, null);
1174 if (methodReference == null)
1175 methodReference = objectType.GetMethod(method, BindingFlags.Instance | BindingFlags.Public);
1176 if (methodReference == null)
1177 throw new InvalidOperationException(objectType.Name + "." + method);
1178 var gr = methodReference.MakeGenericMethod(typeParams);
1179 result = gr.Invoke(target, parameters);
1180 }
1181 else
1182 {
1183 var methodReference = objectType.GetMethod(method, BindingFlags.Static | BindingFlags.Public, null, CallingConventions.Any, System.Type.EmptyTypes, null);
1184 if (methodReference == null)
1185 throw new InvalidOperationException(objectType.Name + "." + method);
1186 var gr = methodReference.MakeGenericMethod(typeParams);
1187 result = gr.Invoke(target, null);
1188 }
1189 return result;
1190 }
1191
1199 public static object CallFactoryMethod(Type objectType, string method, params object[] parameters)
1200 {
1201 object returnValue;
1202 System.Reflection.MethodInfo factory = objectType.GetMethod(
1203 method, factoryFlags, null,
1204 MethodCaller.GetParameterTypes(parameters), null);
1205
1206 if (factory == null)
1207 {
1208 // strongly typed factory couldn't be found
1209 // so find one with the correct number of
1210 // parameters
1211 int parameterCount = parameters.Length;
1212 System.Reflection.MethodInfo[] methods = objectType.GetMethods(factoryFlags);
1213 foreach (System.Reflection.MethodInfo oneMethod in methods)
1214 if (oneMethod.Name == method && oneMethod.GetParameters().Length == parameterCount)
1215 {
1216 factory = oneMethod;
1217 break;
1218 }
1219 }
1220 if (factory == null)
1221 {
1222 // no matching factory could be found
1223 // so throw exception
1224 throw new InvalidOperationException(
1225 string.Format(Resources.NoSuchFactoryMethod, method));
1226 }
1227 try
1228 {
1229 returnValue = factory.Invoke(null, parameters);
1230 }
1231 catch (Exception ex)
1232 {
1233 Exception inner;
1234 if (ex.InnerException == null)
1235 inner = ex;
1236 else
1237 inner = ex.InnerException;
1238 throw new CallMethodException(objectType.Name + "." + factory.Name + " " + Resources.MethodCallFailed, inner);
1239 }
1240 return returnValue;
1241 }
1242
1249 public static System.Reflection.MethodInfo GetNonPublicMethod(Type objectType, string method)
1250 {
1251 var result = FindMethod(objectType, method, privateMethodFlags);
1252 return result;
1253 }
1254
1262 public static System.Reflection.MethodInfo FindMethod(Type objType, string method, BindingFlags flags)
1263 {
1264 System.Reflection.MethodInfo info;
1265 do
1266 {
1267 // find for a strongly typed match
1268 info = objType.GetMethod(method, flags);
1269 if (info != null)
1270 break; // match found
1271 objType = objType.BaseType;
1272 } while (objType != null);
1273
1274 return info;
1275 }
1276 }
1277}
A strongly-typed resource class, for looking up localized strings, etc.
static string MethodNotImplemented
Looks up a localized string similar to not implemented.
static string MemberNotFoundException
Looks up a localized string similar to Member not found on object ({0}).
static string MethodCallFailed
Looks up a localized string similar to method call failed.
static string NoSuchFactoryMethod
Looks up a localized string similar to No such factory method:{0}.
static string TaskOfObjectException
Looks up a localized string similar to Method {0} must return Task<object>.
delegate object DynamicCtorDelegate()
Delegate for a dynamic constructor method.