RuntimePropertyInfo.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. //
  2. // RuntimePropertyInfo.cs: The class used to represent Properties from the mono runtime.
  3. //
  4. // Authors:
  5. // Paolo Molaro ([email protected])
  6. // Patrik Torstensson ([email protected])
  7. // Marek Safar ([email protected])
  8. //
  9. // (C) 2001 Ximian, Inc. http://www.ximian.com
  10. // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
  11. // Copyright 2013 Xamarin, Inc (http://www.xamarin.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.Collections.Generic;
  33. using System.Globalization;
  34. using System.Runtime.CompilerServices;
  35. using System.Runtime.InteropServices;
  36. using System.Runtime.Serialization;
  37. using System.Security;
  38. using System.Text;
  39. using System.Diagnostics.Contracts;
  40. using Mono;
  41. namespace System.Reflection {
  42. internal struct MonoPropertyInfo {
  43. public Type parent;
  44. public Type declaring_type;
  45. public String name;
  46. public MethodInfo get_method;
  47. public MethodInfo set_method;
  48. public PropertyAttributes attrs;
  49. }
  50. [Flags]
  51. internal enum PInfo {
  52. Attributes = 1,
  53. GetMethod = 1 << 1,
  54. SetMethod = 1 << 2,
  55. ReflectedType = 1 << 3,
  56. DeclaringType = 1 << 4,
  57. Name = 1 << 5
  58. }
  59. internal delegate object GetterAdapter (object _this);
  60. internal delegate R Getter<T,R> (T _this);
  61. [Serializable]
  62. [StructLayout (LayoutKind.Sequential)]
  63. internal class RuntimePropertyInfo : PropertyInfo
  64. #if !NETCORE
  65. , ISerializable
  66. #endif
  67. {
  68. #pragma warning disable 649
  69. internal IntPtr klass;
  70. internal IntPtr prop;
  71. MonoPropertyInfo info;
  72. PInfo cached;
  73. GetterAdapter cached_getter;
  74. #pragma warning restore 649
  75. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  76. internal static extern void get_property_info (RuntimePropertyInfo prop, ref MonoPropertyInfo info,
  77. PInfo req_info);
  78. [MethodImplAttribute (MethodImplOptions.InternalCall)]
  79. internal static extern Type[] GetTypeModifiers (RuntimePropertyInfo prop, bool optional);
  80. [MethodImplAttribute (MethodImplOptions.InternalCall)]
  81. internal static extern object get_default_value (RuntimePropertyInfo prop);
  82. internal BindingFlags BindingFlags {
  83. get {
  84. return 0;
  85. }
  86. }
  87. public override Module Module {
  88. get {
  89. return GetRuntimeModule ();
  90. }
  91. }
  92. internal RuntimeType GetDeclaringTypeInternal ()
  93. {
  94. return (RuntimeType) DeclaringType;
  95. }
  96. RuntimeType ReflectedTypeInternal {
  97. get {
  98. return (RuntimeType) ReflectedType;
  99. }
  100. }
  101. internal RuntimeModule GetRuntimeModule ()
  102. {
  103. return GetDeclaringTypeInternal ().GetRuntimeModule ();
  104. }
  105. #region Object Overrides
  106. public override String ToString()
  107. {
  108. return FormatNameAndSig(false);
  109. }
  110. private string FormatNameAndSig(bool serialization)
  111. {
  112. #if NETCORE
  113. throw new NotImplementedException ();
  114. #else
  115. StringBuilder sbName = new StringBuilder(PropertyType.FormatTypeName(serialization));
  116. sbName.Append(" ");
  117. sbName.Append(Name);
  118. var pi = GetIndexParameters ();
  119. if (pi.Length > 0) {
  120. sbName.Append (" [");
  121. RuntimeParameterInfo.FormatParameters (sbName, pi, 0, serialization);
  122. sbName.Append ("]");
  123. }
  124. return sbName.ToString();
  125. #endif
  126. }
  127. #endregion
  128. #if !NETCORE
  129. #region ISerializable Implementation
  130. public void GetObjectData(SerializationInfo info, StreamingContext context)
  131. {
  132. if (info == null)
  133. throw new ArgumentNullException("info");
  134. Contract.EndContractBlock();
  135. MemberInfoSerializationHolder.GetSerializationInfo(
  136. info,
  137. Name,
  138. ReflectedTypeInternal,
  139. ToString(),
  140. SerializationToString(),
  141. MemberTypes.Property,
  142. null);
  143. }
  144. internal string SerializationToString()
  145. {
  146. return FormatNameAndSig(true);
  147. }
  148. #endregion
  149. #endif
  150. void CachePropertyInfo (PInfo flags)
  151. {
  152. if ((cached & flags) != flags) {
  153. get_property_info (this, ref info, flags);
  154. cached |= flags;
  155. }
  156. }
  157. public override PropertyAttributes Attributes {
  158. get {
  159. CachePropertyInfo (PInfo.Attributes);
  160. return info.attrs;
  161. }
  162. }
  163. public override bool CanRead {
  164. get {
  165. CachePropertyInfo (PInfo.GetMethod);
  166. return (info.get_method != null);
  167. }
  168. }
  169. public override bool CanWrite {
  170. get {
  171. CachePropertyInfo (PInfo.SetMethod);
  172. return (info.set_method != null);
  173. }
  174. }
  175. public override Type PropertyType {
  176. get {
  177. CachePropertyInfo (PInfo.GetMethod | PInfo.SetMethod);
  178. if (info.get_method != null) {
  179. return info.get_method.ReturnType;
  180. } else {
  181. ParameterInfo[] parameters = info.set_method.GetParametersInternal ();
  182. return parameters [parameters.Length - 1].ParameterType;
  183. }
  184. }
  185. }
  186. public override Type ReflectedType {
  187. get {
  188. CachePropertyInfo (PInfo.ReflectedType);
  189. return info.parent;
  190. }
  191. }
  192. public override Type DeclaringType {
  193. get {
  194. CachePropertyInfo (PInfo.DeclaringType);
  195. return info.declaring_type;
  196. }
  197. }
  198. public override string Name {
  199. get {
  200. CachePropertyInfo (PInfo.Name);
  201. return info.name;
  202. }
  203. }
  204. public override MethodInfo[] GetAccessors (bool nonPublic)
  205. {
  206. int nget = 0;
  207. int nset = 0;
  208. CachePropertyInfo (PInfo.GetMethod | PInfo.SetMethod);
  209. if (info.set_method != null && (nonPublic || info.set_method.IsPublic))
  210. nset = 1;
  211. if (info.get_method != null && (nonPublic || info.get_method.IsPublic))
  212. nget = 1;
  213. MethodInfo[] res = new MethodInfo [nget + nset];
  214. int n = 0;
  215. if (nset != 0)
  216. res [n++] = info.set_method;
  217. if (nget != 0)
  218. res [n++] = info.get_method;
  219. return res;
  220. }
  221. public override MethodInfo GetGetMethod (bool nonPublic)
  222. {
  223. CachePropertyInfo (PInfo.GetMethod);
  224. if (info.get_method != null && (nonPublic || info.get_method.IsPublic))
  225. return info.get_method;
  226. else
  227. return null;
  228. }
  229. public override ParameterInfo[] GetIndexParameters ()
  230. {
  231. CachePropertyInfo (PInfo.GetMethod | PInfo.SetMethod);
  232. ParameterInfo[] src;
  233. int length;
  234. if (info.get_method != null) {
  235. src = info.get_method.GetParametersInternal ();
  236. length = src.Length;
  237. } else if (info.set_method != null) {
  238. src = info.set_method.GetParametersInternal ();
  239. length = src.Length - 1;
  240. } else
  241. return EmptyArray<ParameterInfo>.Value;
  242. var dest = new ParameterInfo [length];
  243. for (int i = 0; i < length; ++i) {
  244. dest [i] = RuntimeParameterInfo.New (src [i], this);
  245. }
  246. return dest;
  247. }
  248. public override MethodInfo GetSetMethod (bool nonPublic)
  249. {
  250. CachePropertyInfo (PInfo.SetMethod);
  251. if (info.set_method != null && (nonPublic || info.set_method.IsPublic))
  252. return info.set_method;
  253. else
  254. return null;
  255. }
  256. /*TODO verify for attribute based default values, just like ParameterInfo*/
  257. public override object GetConstantValue ()
  258. {
  259. return get_default_value (this);
  260. }
  261. public override object GetRawConstantValue() {
  262. return get_default_value (this);
  263. }
  264. // According to MSDN the inherit parameter is ignored here and
  265. // the behavior always defaults to inherit = false
  266. //
  267. public override bool IsDefined (Type attributeType, bool inherit)
  268. {
  269. return MonoCustomAttrs.IsDefined (this, attributeType, false);
  270. }
  271. public override object[] GetCustomAttributes (bool inherit)
  272. {
  273. return MonoCustomAttrs.GetCustomAttributes (this, false);
  274. }
  275. public override object[] GetCustomAttributes (Type attributeType, bool inherit)
  276. {
  277. return MonoCustomAttrs.GetCustomAttributes (this, attributeType, false);
  278. }
  279. delegate object GetterAdapter (object _this);
  280. delegate R Getter<T,R> (T _this);
  281. delegate R StaticGetter<R> ();
  282. #pragma warning disable 169
  283. // Used via reflection
  284. static object GetterAdapterFrame<T,R> (Getter<T,R> getter, object obj)
  285. {
  286. return getter ((T)obj);
  287. }
  288. static object StaticGetterAdapterFrame<R> (StaticGetter<R> getter, object obj)
  289. {
  290. return getter ();
  291. }
  292. #pragma warning restore 169
  293. /*
  294. * The idea behing this optimization is to use a pair of delegates to simulate the same effect of doing a reflection call.
  295. * The first delegate cast the this argument to the right type and the second does points to the target method.
  296. */
  297. static GetterAdapter CreateGetterDelegate (MethodInfo method)
  298. {
  299. Type[] typeVector;
  300. Type getterType;
  301. object getterDelegate;
  302. MethodInfo adapterFrame;
  303. Type getterDelegateType;
  304. string frameName;
  305. if (method.IsStatic) {
  306. typeVector = new Type[] { method.ReturnType };
  307. getterDelegateType = typeof (StaticGetter<>);
  308. frameName = "StaticGetterAdapterFrame";
  309. } else {
  310. typeVector = new Type[] { method.DeclaringType, method.ReturnType };
  311. getterDelegateType = typeof (Getter<,>);
  312. frameName = "GetterAdapterFrame";
  313. }
  314. getterType = getterDelegateType.MakeGenericType (typeVector);
  315. getterDelegate = Delegate.CreateDelegate (getterType, method);
  316. adapterFrame = typeof (RuntimePropertyInfo).GetMethod (frameName, BindingFlags.Static | BindingFlags.NonPublic);
  317. adapterFrame = adapterFrame.MakeGenericMethod (typeVector);
  318. return (GetterAdapter)Delegate.CreateDelegate (typeof (GetterAdapter), getterDelegate, adapterFrame, true);
  319. }
  320. public override object GetValue (object obj, object[] index)
  321. {
  322. if (index == null || index.Length == 0) {
  323. /*FIXME we should check if the number of arguments matches the expected one, otherwise the error message will be pretty criptic.*/
  324. #if !FULL_AOT_RUNTIME
  325. if (cached_getter == null) {
  326. MethodInfo method = GetGetMethod (true);
  327. if (method == null)
  328. throw new ArgumentException ($"Get Method not found for '{Name}'");
  329. if (!DeclaringType.IsValueType && !method.ContainsGenericParameters) { //FIXME find a way to build an invoke delegate for value types.
  330. cached_getter = CreateGetterDelegate (method);
  331. // The try-catch preserves the .Invoke () behaviour
  332. try {
  333. return cached_getter (obj);
  334. } catch (Exception ex) {
  335. throw new TargetInvocationException (ex);
  336. }
  337. }
  338. } else {
  339. try {
  340. return cached_getter (obj);
  341. } catch (Exception ex) {
  342. throw new TargetInvocationException (ex);
  343. }
  344. }
  345. #endif
  346. }
  347. return GetValue (obj, BindingFlags.Default, null, index, null);
  348. }
  349. public override object GetValue (object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)
  350. {
  351. object ret = null;
  352. MethodInfo method = GetGetMethod (true);
  353. if (method == null)
  354. throw new ArgumentException ($"Get Method not found for '{Name}'");
  355. try {
  356. if (index == null || index.Length == 0)
  357. ret = method.Invoke (obj, invokeAttr, binder, null, culture);
  358. else
  359. ret = method.Invoke (obj, invokeAttr, binder, index, culture);
  360. }
  361. catch (SecurityException se) {
  362. throw new TargetInvocationException (se);
  363. }
  364. return ret;
  365. }
  366. public override void SetValue (object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)
  367. {
  368. MethodInfo method = GetSetMethod (true);
  369. if (method == null)
  370. throw new ArgumentException ("Set Method not found for '" + Name + "'");
  371. object [] parms;
  372. if (index == null || index.Length == 0)
  373. parms = new object [] {value};
  374. else {
  375. int ilen = index.Length;
  376. parms = new object [ilen+ 1];
  377. index.CopyTo (parms, 0);
  378. parms [ilen] = value;
  379. }
  380. method.Invoke (obj, invokeAttr, binder, parms, culture);
  381. }
  382. public override Type[] GetOptionalCustomModifiers () => GetCustomModifiers (true);
  383. public override Type[] GetRequiredCustomModifiers () => GetCustomModifiers (false);
  384. private Type[] GetCustomModifiers (bool optional) => GetTypeModifiers (this, optional) ?? Type.EmptyTypes;
  385. public override IList<CustomAttributeData> GetCustomAttributesData () {
  386. return CustomAttributeData.GetCustomAttributes (this);
  387. }
  388. #if !NETCORE
  389. public sealed override bool HasSameMetadataDefinitionAs (MemberInfo other) => HasSameMetadataDefinitionAsCore<RuntimePropertyInfo> (other);
  390. #endif
  391. public override int MetadataToken {
  392. get {
  393. return get_metadata_token (this);
  394. }
  395. }
  396. [MethodImplAttribute (MethodImplOptions.InternalCall)]
  397. internal static extern int get_metadata_token (RuntimePropertyInfo monoProperty);
  398. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  399. private static extern PropertyInfo internal_from_handle_type (IntPtr event_handle, IntPtr type_handle);
  400. internal static PropertyInfo GetPropertyFromHandle (RuntimePropertyHandle handle, RuntimeTypeHandle reflectedType)
  401. {
  402. if (handle.Value == IntPtr.Zero)
  403. throw new ArgumentException ("The handle is invalid.");
  404. PropertyInfo pi = internal_from_handle_type (handle.Value, reflectedType.Value);
  405. if (pi == null)
  406. throw new ArgumentException ("The property handle and the type handle are incompatible.");
  407. return pi;
  408. }
  409. }
  410. }