Binder.cs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. // System.Reflection.Binder
  2. //
  3. // Sean MacIsaac ([email protected])
  4. // Paolo Molaro ([email protected])
  5. //
  6. // (C) Ximian, Inc. 2001 - 2002
  7. using System.Globalization;
  8. namespace System.Reflection
  9. {
  10. [Serializable]
  11. public abstract class Binder
  12. {
  13. protected Binder () {}
  14. public abstract FieldInfo BindToField (BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture);
  15. public abstract MethodBase BindToMethod (BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state);
  16. public abstract object ChangeType (object value, Type type, CultureInfo culture);
  17. public abstract void ReorderArgumentArray( ref object[] args, object state);
  18. public abstract MethodBase SelectMethod (BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers);
  19. public abstract PropertyInfo SelectProperty( BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers);
  20. static Binder default_binder;
  21. internal static Binder DefaultBinder {
  22. get {
  23. if (null == default_binder)
  24. {
  25. lock (typeof (Binder))
  26. {
  27. if (default_binder == null)
  28. default_binder = new Default ();
  29. return default_binder;
  30. }
  31. }
  32. return default_binder;
  33. }
  34. }
  35. internal static bool ConvertArgs (Binder binder, object[] args, ParameterInfo[] pinfo, CultureInfo culture) {
  36. if (args == null) {
  37. if ( pinfo.Length == 0)
  38. return true;
  39. else
  40. throw new TargetParameterCountException ();
  41. }
  42. if (pinfo.Length != args.Length)
  43. throw new TargetParameterCountException ();
  44. for (int i = 0; i < args.Length; ++i) {
  45. object v = binder.ChangeType (args [i], pinfo[i].ParameterType, culture);
  46. if ((v == null) && (args [i] != null))
  47. return false;
  48. args [i] = v;
  49. }
  50. return true;
  51. }
  52. internal sealed class Default : Binder {
  53. public override FieldInfo BindToField (BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture)
  54. {
  55. if (match == null)
  56. throw new ArgumentNullException ("match");
  57. foreach (FieldInfo f in match) {
  58. if (check_type (value.GetType (), f.FieldType))
  59. return f;
  60. }
  61. return null;
  62. }
  63. [MonoTODO]
  64. public override MethodBase BindToMethod (BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state)
  65. {
  66. Type[] types;
  67. if (args == null)
  68. types = Type.EmptyTypes;
  69. else {
  70. types = new Type [args.Length];
  71. for (int i = 0; i < args.Length; ++i) {
  72. if (args [i] != null)
  73. types [i] = args [i].GetType ();
  74. }
  75. }
  76. MethodBase selected = SelectMethod (bindingAttr, match, types, modifiers);
  77. state = null;
  78. return selected;
  79. }
  80. static bool IsArrayAssignable (Type object_type, Type target_type)
  81. {
  82. if (object_type.IsArray && target_type.IsArray)
  83. return IsArrayAssignable (object_type.GetElementType (), target_type.GetElementType ());
  84. if (target_type.IsAssignableFrom (object_type))
  85. return true;
  86. return false;
  87. }
  88. public override object ChangeType (object value, Type type, CultureInfo culture)
  89. {
  90. if (value == null)
  91. return null;
  92. Type vtype = value.GetType ();
  93. if (vtype == type || type.IsAssignableFrom (vtype))
  94. return value;
  95. if (vtype.IsArray && type.IsArray){
  96. if (IsArrayAssignable (vtype.GetElementType (), type.GetElementType ()))
  97. return value;
  98. }
  99. if (check_type (vtype, type))
  100. return Convert.ChangeType (value, type);
  101. return null;
  102. }
  103. [MonoTODO]
  104. public override void ReorderArgumentArray (ref object[] args, object state)
  105. {
  106. //do nothing until we support named arguments
  107. //throw new NotImplementedException ();
  108. }
  109. private static bool check_type (Type from, Type to) {
  110. if (from == to)
  111. return true;
  112. TypeCode fromt = Type.GetTypeCode (from);
  113. TypeCode tot = Type.GetTypeCode (to);
  114. switch (fromt) {
  115. case TypeCode.Char:
  116. switch (tot) {
  117. case TypeCode.UInt16:
  118. case TypeCode.UInt32:
  119. case TypeCode.Int32:
  120. case TypeCode.UInt64:
  121. case TypeCode.Int64:
  122. case TypeCode.Single:
  123. case TypeCode.Double:
  124. return true;
  125. }
  126. return to == typeof (object);
  127. case TypeCode.Byte:
  128. switch (tot) {
  129. case TypeCode.Char:
  130. case TypeCode.UInt16:
  131. case TypeCode.Int16:
  132. case TypeCode.UInt32:
  133. case TypeCode.Int32:
  134. case TypeCode.UInt64:
  135. case TypeCode.Int64:
  136. case TypeCode.Single:
  137. case TypeCode.Double:
  138. return true;
  139. }
  140. return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
  141. case TypeCode.SByte:
  142. switch (tot) {
  143. case TypeCode.Int16:
  144. case TypeCode.Int32:
  145. case TypeCode.Int64:
  146. case TypeCode.Single:
  147. case TypeCode.Double:
  148. return true;
  149. }
  150. return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
  151. case TypeCode.UInt16:
  152. switch (tot) {
  153. case TypeCode.UInt32:
  154. case TypeCode.Int32:
  155. case TypeCode.UInt64:
  156. case TypeCode.Int64:
  157. case TypeCode.Single:
  158. case TypeCode.Double:
  159. return true;
  160. }
  161. return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
  162. case TypeCode.Int16:
  163. switch (tot) {
  164. case TypeCode.Int32:
  165. case TypeCode.Int64:
  166. case TypeCode.Single:
  167. case TypeCode.Double:
  168. return true;
  169. }
  170. return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
  171. case TypeCode.UInt32:
  172. switch (tot) {
  173. case TypeCode.UInt64:
  174. case TypeCode.Int64:
  175. case TypeCode.Single:
  176. case TypeCode.Double:
  177. return true;
  178. }
  179. return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
  180. case TypeCode.Int32:
  181. switch (tot) {
  182. case TypeCode.Int64:
  183. case TypeCode.Single:
  184. case TypeCode.Double:
  185. return true;
  186. }
  187. return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
  188. case TypeCode.UInt64:
  189. case TypeCode.Int64:
  190. switch (tot) {
  191. case TypeCode.Single:
  192. case TypeCode.Double:
  193. return true;
  194. }
  195. return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
  196. case TypeCode.Single:
  197. return tot == TypeCode.Double || to == typeof (object);
  198. default:
  199. /* TODO: handle valuetype -> byref */
  200. if (to == typeof (object) && from.IsValueType)
  201. return true;
  202. return to.IsAssignableFrom (from);
  203. }
  204. }
  205. private static bool check_arguments (Type[] types, ParameterInfo[] args) {
  206. for (int i = 0; i < types.Length; ++i) {
  207. if (!check_type (types [i], args [i].ParameterType))
  208. return false;
  209. }
  210. return true;
  211. }
  212. public override MethodBase SelectMethod (BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
  213. {
  214. MethodBase m;
  215. int i, j;
  216. if (match == null)
  217. throw new ArgumentNullException ("match");
  218. /* first look for an exact match... */
  219. for (i = 0; i < match.Length; ++i) {
  220. m = match [i];
  221. ParameterInfo[] args = m.GetParameters ();
  222. if (args.Length != types.Length)
  223. continue;
  224. for (j = 0; j < types.Length; ++j) {
  225. if (types [j] != args [j].ParameterType)
  226. break;
  227. }
  228. if (j == types.Length)
  229. return m;
  230. }
  231. for (i = 0; i < match.Length; ++i) {
  232. m = match [i];
  233. ParameterInfo[] args = m.GetParameters ();
  234. if (args.Length != types.Length)
  235. continue;
  236. if (!check_arguments (types, args))
  237. continue;
  238. return m;
  239. }
  240. return null;
  241. }
  242. public override PropertyInfo SelectProperty (BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers)
  243. {
  244. if (match == null)
  245. throw new ArgumentNullException ("match");
  246. foreach (PropertyInfo m in match) {
  247. ParameterInfo[] args = m.GetIndexParameters ();
  248. if (args.Length != indexes.Length)
  249. continue;
  250. if (!check_arguments (indexes, args))
  251. continue;
  252. return m;
  253. }
  254. return null;
  255. }
  256. }
  257. }
  258. }