Binder.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  1. // System.Reflection.Binder
  2. //
  3. // Authors:
  4. // Sean MacIsaac ([email protected])
  5. // Paolo Molaro ([email protected])
  6. // Gonzalo Paniagua Javier ([email protected])
  7. //
  8. // (C) Ximian, Inc. 2001 - 2003
  9. // (c) Copyright 2004 Novell, Inc. (http://www.novell.com)
  10. //
  11. // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
  12. //
  13. // Permission is hereby granted, free of charge, to any person obtaining
  14. // a copy of this software and associated documentation files (the
  15. // "Software"), to deal in the Software without restriction, including
  16. // without limitation the rights to use, copy, modify, merge, publish,
  17. // distribute, sublicense, and/or sell copies of the Software, and to
  18. // permit persons to whom the Software is furnished to do so, subject to
  19. // the following conditions:
  20. //
  21. // The above copyright notice and this permission notice shall be
  22. // included in all copies or substantial portions of the Software.
  23. //
  24. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  25. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  26. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  27. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  28. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  29. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  30. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  31. //
  32. using System.Globalization;
  33. using System.Runtime.InteropServices;
  34. namespace System.Reflection
  35. {
  36. #if NET_2_0
  37. [ComVisible (true)]
  38. #endif
  39. [Serializable]
  40. [ClassInterface(ClassInterfaceType.AutoDual)]
  41. public abstract class Binder
  42. {
  43. protected Binder () {}
  44. public abstract FieldInfo BindToField (BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture);
  45. public abstract MethodBase BindToMethod (BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state);
  46. public abstract object ChangeType (object value, Type type, CultureInfo culture);
  47. public abstract void ReorderArgumentArray( ref object[] args, object state);
  48. public abstract MethodBase SelectMethod (BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers);
  49. public abstract PropertyInfo SelectProperty( BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers);
  50. static Binder default_binder = new Default ();
  51. internal static Binder DefaultBinder {
  52. get {
  53. return default_binder;
  54. }
  55. }
  56. internal static bool ConvertArgs (Binder binder, object[] args, ParameterInfo[] pinfo, CultureInfo culture) {
  57. if (args == null) {
  58. if ( pinfo.Length == 0)
  59. return true;
  60. else
  61. throw new TargetParameterCountException ();
  62. }
  63. if (pinfo.Length != args.Length)
  64. throw new TargetParameterCountException ();
  65. for (int i = 0; i < args.Length; ++i) {
  66. object v = binder.ChangeType (args [i], pinfo[i].ParameterType, culture);
  67. if ((v == null) && (args [i] != null))
  68. return false;
  69. args [i] = v;
  70. }
  71. return true;
  72. }
  73. internal static int GetDerivedLevel (Type type)
  74. {
  75. Type searchType = type;
  76. int level = 1;
  77. while (searchType.BaseType != null)
  78. {
  79. level++;
  80. searchType = searchType.BaseType;
  81. }
  82. return level;
  83. }
  84. internal static MethodBase FindMostDerivedMatch (MethodBase [] match)
  85. {
  86. int highLevel = 0;
  87. int matchId = -1;
  88. int count = match.Length;
  89. for (int current = 0; current < count; current++)
  90. {
  91. int level = GetDerivedLevel (match[current].DeclaringType);
  92. if (level == highLevel)
  93. throw new AmbiguousMatchException ();
  94. if (level > highLevel)
  95. {
  96. highLevel = level;
  97. matchId = current;
  98. }
  99. }
  100. return match[matchId];
  101. }
  102. internal sealed class Default : Binder {
  103. public override FieldInfo BindToField (BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture)
  104. {
  105. if (match == null)
  106. throw new ArgumentNullException ("match");
  107. foreach (FieldInfo f in match) {
  108. if (check_type (value.GetType (), f.FieldType))
  109. return f;
  110. }
  111. return null;
  112. }
  113. //
  114. // FIXME: There was a MonoTODO, but it does not explain what the problem is
  115. //
  116. public override MethodBase BindToMethod (BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state)
  117. {
  118. Type[] types;
  119. if (args == null)
  120. types = Type.EmptyTypes;
  121. else {
  122. types = new Type [args.Length];
  123. for (int i = 0; i < args.Length; ++i) {
  124. if (args [i] != null)
  125. types [i] = args [i].GetType ();
  126. }
  127. }
  128. MethodBase selected = SelectMethod (bindingAttr, match, types, modifiers);
  129. state = null;
  130. if (names != null)
  131. ReorderParameters (names, ref args, selected);
  132. return selected;
  133. }
  134. void ReorderParameters (string [] names, ref object [] args, MethodBase selected)
  135. {
  136. object [] newArgs = new object [args.Length];
  137. Array.Copy (args, newArgs, args.Length);
  138. ParameterInfo [] plist = selected.GetParameters ();
  139. for (int n = 0; n < names.Length; n++)
  140. for (int p = 0; p < plist.Length; p++) {
  141. if (names [n] == plist [p].Name) {
  142. newArgs [p] = args [n];
  143. break;
  144. }
  145. }
  146. Array.Copy (newArgs, args, args.Length);
  147. }
  148. static bool IsArrayAssignable (Type object_type, Type target_type)
  149. {
  150. if (object_type.IsArray && target_type.IsArray)
  151. return IsArrayAssignable (object_type.GetElementType (), target_type.GetElementType ());
  152. if (target_type.IsAssignableFrom (object_type))
  153. return true;
  154. return false;
  155. }
  156. public override object ChangeType (object value, Type type, CultureInfo culture)
  157. {
  158. if (value == null)
  159. return null;
  160. Type vtype = value.GetType ();
  161. if (type.IsByRef)
  162. type = type.GetElementType ();
  163. if (vtype == type || type.IsInstanceOfType (value))
  164. return value;
  165. if (vtype.IsArray && type.IsArray){
  166. if (IsArrayAssignable (vtype.GetElementType (), type.GetElementType ()))
  167. return value;
  168. }
  169. if (check_type (vtype, type))
  170. return Convert.ChangeType (value, type);
  171. return null;
  172. }
  173. [MonoTODO ("This method does not do anything in Mono")]
  174. public override void ReorderArgumentArray (ref object[] args, object state)
  175. {
  176. //do nothing until we support named arguments
  177. //throw new NotImplementedException ();
  178. }
  179. private static bool check_type (Type from, Type to) {
  180. if (from == to)
  181. return true;
  182. if (from == null)
  183. return true;
  184. TypeCode fromt = Type.GetTypeCode (from);
  185. TypeCode tot = Type.GetTypeCode (to);
  186. if (to.IsByRef != from.IsByRef)
  187. return false;
  188. if (to.IsInterface)
  189. return to.IsAssignableFrom (from);
  190. switch (fromt) {
  191. case TypeCode.Char:
  192. switch (tot) {
  193. case TypeCode.UInt16:
  194. case TypeCode.UInt32:
  195. case TypeCode.Int32:
  196. case TypeCode.UInt64:
  197. case TypeCode.Int64:
  198. case TypeCode.Single:
  199. case TypeCode.Double:
  200. return true;
  201. }
  202. return to == typeof (object);
  203. case TypeCode.Byte:
  204. switch (tot) {
  205. case TypeCode.Char:
  206. case TypeCode.UInt16:
  207. case TypeCode.Int16:
  208. case TypeCode.UInt32:
  209. case TypeCode.Int32:
  210. case TypeCode.UInt64:
  211. case TypeCode.Int64:
  212. case TypeCode.Single:
  213. case TypeCode.Double:
  214. return true;
  215. }
  216. return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
  217. case TypeCode.SByte:
  218. switch (tot) {
  219. case TypeCode.Int16:
  220. case TypeCode.Int32:
  221. case TypeCode.Int64:
  222. case TypeCode.Single:
  223. case TypeCode.Double:
  224. return true;
  225. }
  226. return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
  227. case TypeCode.UInt16:
  228. switch (tot) {
  229. case TypeCode.UInt32:
  230. case TypeCode.Int32:
  231. case TypeCode.UInt64:
  232. case TypeCode.Int64:
  233. case TypeCode.Single:
  234. case TypeCode.Double:
  235. return true;
  236. }
  237. return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
  238. case TypeCode.Int16:
  239. switch (tot) {
  240. case TypeCode.Int32:
  241. case TypeCode.Int64:
  242. case TypeCode.Single:
  243. case TypeCode.Double:
  244. return true;
  245. }
  246. return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
  247. case TypeCode.UInt32:
  248. switch (tot) {
  249. case TypeCode.UInt64:
  250. case TypeCode.Int64:
  251. case TypeCode.Single:
  252. case TypeCode.Double:
  253. return true;
  254. }
  255. return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
  256. case TypeCode.Int32:
  257. switch (tot) {
  258. case TypeCode.Int64:
  259. case TypeCode.Single:
  260. case TypeCode.Double:
  261. return true;
  262. }
  263. return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
  264. case TypeCode.UInt64:
  265. case TypeCode.Int64:
  266. switch (tot) {
  267. case TypeCode.Single:
  268. case TypeCode.Double:
  269. return true;
  270. }
  271. return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
  272. case TypeCode.Single:
  273. return tot == TypeCode.Double || to == typeof (object);
  274. default:
  275. /* TODO: handle valuetype -> byref */
  276. if (to == typeof (object) && from.IsValueType)
  277. return true;
  278. return to.IsAssignableFrom (from);
  279. }
  280. }
  281. private static bool check_arguments (Type[] types, ParameterInfo[] args) {
  282. for (int i = 0; i < types.Length; ++i) {
  283. if (!check_type (types [i], args [i].ParameterType))
  284. return false;
  285. }
  286. return true;
  287. }
  288. public override MethodBase SelectMethod (BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
  289. {
  290. MethodBase m;
  291. int i, j;
  292. if (match == null)
  293. throw new ArgumentNullException ("match");
  294. bool isdefParamArray = false;
  295. Type elementType = null;
  296. /* first look for an exact match... */
  297. for (i = 0; i < match.Length; ++i) {
  298. m = match [i];
  299. ParameterInfo[] args = m.GetParameters ();
  300. if (args.Length > types.Length)
  301. continue;
  302. else if(args.Length <= types.Length & args.Length > 0)
  303. {
  304. isdefParamArray = Attribute.IsDefined (args [args.Length - 1], typeof (ParamArrayAttribute));
  305. if (isdefParamArray)
  306. elementType = args [args.Length - 1].ParameterType.GetElementType ();
  307. if (args.Length != types.Length & !isdefParamArray)
  308. continue;
  309. }else if(args.Length == 0 & types.Length > 0)
  310. continue;
  311. for (j = 0; j < types.Length; ++j) {
  312. if (!isdefParamArray && types [j] != args [j].ParameterType)
  313. break;
  314. else if (isdefParamArray) {
  315. if (j < (args.Length - 1) && types [j] != args [j].ParameterType)
  316. break;
  317. else if (j >= (args.Length - 1) && types [j] != elementType)
  318. break;
  319. }
  320. }
  321. if (j == types.Length)
  322. return m;
  323. }
  324. if ((int)(bindingAttr & BindingFlags.ExactBinding) != 0)
  325. return null;
  326. MethodBase result = null;
  327. for (i = 0; i < match.Length; ++i) {
  328. m = match [i];
  329. ParameterInfo[] args = m.GetParameters ();
  330. if (args.Length != types.Length)
  331. continue;
  332. if (!check_arguments (types, args))
  333. continue;
  334. if (result != null)
  335. result = GetBetterMethod (result, m, types);
  336. else
  337. result = m;
  338. }
  339. return result;
  340. }
  341. MethodBase GetBetterMethod (MethodBase m1, MethodBase m2, Type [] types)
  342. {
  343. #if NET_2_0
  344. if (m1.IsGenericMethodDefinition &&
  345. !m2.IsGenericMethodDefinition)
  346. return m2;
  347. if (m2.IsGenericMethodDefinition &&
  348. !m1.IsGenericMethodDefinition)
  349. return m1;
  350. #endif
  351. ParameterInfo [] pl1 = m1.GetParameters ();
  352. ParameterInfo [] pl2 = m2.GetParameters ();
  353. int prev = 0;
  354. for (int i = 0; i < pl1.Length; i++) {
  355. int cmp = CompareCloserType (pl1 [i].ParameterType, pl2 [i].ParameterType);
  356. if (cmp != 0 && prev != 0 && prev != cmp)
  357. throw new AmbiguousMatchException ();
  358. if (cmp != 0)
  359. prev = cmp;
  360. }
  361. if (prev != 0)
  362. return prev > 0 ? m2 : m1;
  363. Type dt1 = m1.DeclaringType;
  364. Type dt2 = m2.DeclaringType;
  365. if (dt1 != dt2) {
  366. if (dt1.IsSubclassOf(dt2))
  367. return m1;
  368. if (dt2.IsSubclassOf(dt1))
  369. return m2;
  370. }
  371. bool va1 = (m1.CallingConvention & CallingConventions.VarArgs) != 0;
  372. bool va2 = (m2.CallingConvention & CallingConventions.VarArgs) != 0;
  373. if (va1 && !va2)
  374. return m2;
  375. if (va2 && !va1)
  376. return m1;
  377. throw new AmbiguousMatchException ();
  378. }
  379. int CompareCloserType (Type t1, Type t2)
  380. {
  381. if (t1 == t2)
  382. return 0;
  383. #if NET_2_0
  384. if (t1.IsGenericParameter && !t2.IsGenericParameter)
  385. return 1; // t2
  386. if (!t1.IsGenericParameter && t2.IsGenericParameter)
  387. return -1; // t1
  388. #endif
  389. if (t1.HasElementType && t2.HasElementType)
  390. return CompareCloserType (
  391. t1.GetElementType (),
  392. t2.GetElementType ());
  393. if (t1.IsSubclassOf (t2))
  394. return -1; // t1
  395. if (t2.IsSubclassOf (t1))
  396. return 1; // t2
  397. if (t1.IsInterface && Array.IndexOf (t2.GetInterfaces (), t1) >= 0)
  398. return 1; // t2
  399. if (t2.IsInterface && Array.IndexOf (t1.GetInterfaces (), t2) >= 0)
  400. return -1; // t1
  401. // What kind of cases could reach here?
  402. return 0;
  403. }
  404. public override PropertyInfo SelectProperty (BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers)
  405. {
  406. if (match == null || match.Length == 0)
  407. throw new ArgumentException ("No properties provided", "match");
  408. bool haveRet = (returnType != null);
  409. int idxlen = (indexes != null) ? indexes.Length : -1;
  410. PropertyInfo result = null;
  411. int i;
  412. int best_score = Int32.MaxValue - 1;
  413. int fail_score = Int32.MaxValue;
  414. int level = 0;
  415. for (i = match.Length - 1; i >= 0; i--) {
  416. PropertyInfo p = match [i];
  417. ParameterInfo[] args = p.GetIndexParameters ();
  418. if (idxlen >= 0 && idxlen != args.Length)
  419. continue;
  420. if (haveRet && !check_type (p.PropertyType, returnType))
  421. continue;
  422. int score = Int32.MaxValue - 1;
  423. if (idxlen > 0) {
  424. score = check_arguments_with_score (indexes, args);
  425. if (score == -1)
  426. continue;
  427. }
  428. int new_level = GetDerivedLevel (p.DeclaringType);
  429. if (result != null) {
  430. if (best_score < score)
  431. continue;
  432. if (best_score == score) {
  433. if (level == new_level) {
  434. // Keep searching. May be there's something
  435. // better for us.
  436. fail_score = score;
  437. continue;
  438. }
  439. if (level > new_level)
  440. continue;
  441. }
  442. }
  443. result = p;
  444. best_score = score;
  445. level = new_level;
  446. }
  447. if (fail_score <= best_score)
  448. throw new AmbiguousMatchException ();
  449. return result;
  450. }
  451. static int check_arguments_with_score (Type [] types, ParameterInfo [] args)
  452. {
  453. int worst = -1;
  454. for (int i = 0; i < types.Length; ++i) {
  455. int res = check_type_with_score (types [i], args [i].ParameterType);
  456. if (res == -1)
  457. return -1;
  458. if (worst < res)
  459. worst = res;
  460. }
  461. return worst;
  462. }
  463. // 0 -> same type or null and !valuetype
  464. // 1 -> to == Enum
  465. // 2 -> value type that don't lose data
  466. // 3 -> to == IsAssignableFrom
  467. // 4 -> to == object
  468. static int check_type_with_score (Type from, Type to)
  469. {
  470. if (from == null)
  471. return to.IsValueType ? -1 : 0;
  472. if (from == to)
  473. return 0;
  474. if (to == typeof (object))
  475. return 4;
  476. TypeCode fromt = Type.GetTypeCode (from);
  477. TypeCode tot = Type.GetTypeCode (to);
  478. switch (fromt) {
  479. case TypeCode.Char:
  480. switch (tot) {
  481. case TypeCode.UInt16:
  482. return 0;
  483. case TypeCode.UInt32:
  484. case TypeCode.Int32:
  485. case TypeCode.UInt64:
  486. case TypeCode.Int64:
  487. case TypeCode.Single:
  488. case TypeCode.Double:
  489. return 2;
  490. }
  491. return -1;
  492. case TypeCode.Byte:
  493. switch (tot) {
  494. case TypeCode.Char:
  495. case TypeCode.UInt16:
  496. case TypeCode.Int16:
  497. case TypeCode.UInt32:
  498. case TypeCode.Int32:
  499. case TypeCode.UInt64:
  500. case TypeCode.Int64:
  501. case TypeCode.Single:
  502. case TypeCode.Double:
  503. return 2;
  504. }
  505. return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
  506. case TypeCode.SByte:
  507. switch (tot) {
  508. case TypeCode.Int16:
  509. case TypeCode.Int32:
  510. case TypeCode.Int64:
  511. case TypeCode.Single:
  512. case TypeCode.Double:
  513. return 2;
  514. }
  515. return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
  516. case TypeCode.UInt16:
  517. switch (tot) {
  518. case TypeCode.UInt32:
  519. case TypeCode.Int32:
  520. case TypeCode.UInt64:
  521. case TypeCode.Int64:
  522. case TypeCode.Single:
  523. case TypeCode.Double:
  524. return 2;
  525. }
  526. return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
  527. case TypeCode.Int16:
  528. switch (tot) {
  529. case TypeCode.Int32:
  530. case TypeCode.Int64:
  531. case TypeCode.Single:
  532. case TypeCode.Double:
  533. return 2;
  534. }
  535. return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
  536. case TypeCode.UInt32:
  537. switch (tot) {
  538. case TypeCode.UInt64:
  539. case TypeCode.Int64:
  540. case TypeCode.Single:
  541. case TypeCode.Double:
  542. return 2;
  543. }
  544. return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
  545. case TypeCode.Int32:
  546. switch (tot) {
  547. case TypeCode.Int64:
  548. case TypeCode.Single:
  549. case TypeCode.Double:
  550. return 2;
  551. }
  552. return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
  553. case TypeCode.UInt64:
  554. case TypeCode.Int64:
  555. switch (tot) {
  556. case TypeCode.Single:
  557. case TypeCode.Double:
  558. return 2;
  559. }
  560. return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
  561. case TypeCode.Single:
  562. return tot == TypeCode.Double ? 2 : -1;
  563. default:
  564. return (to.IsAssignableFrom (from)) ? 3 : -1;
  565. }
  566. }
  567. }
  568. }
  569. }