Fix value returned by PropertyInfo::DeclaringType
[mono.git] / mcs / class / corlib / System.Reflection / MonoProperty.cs
1 //
2 // System.Reflection/MonoProperty.cs
3 // The class used to represent Properties from the mono runtime.
4 //
5 // Author:
6 //   Paolo Molaro (lupus@ximian.com)
7 //   Patrik Torstensson (patrik.torstensson@labs2.com)
8 //
9 // (C) 2001 Ximian, Inc.  http://www.ximian.com
10 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
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
39 namespace System.Reflection {
40         
41         internal struct MonoPropertyInfo {
42                 public Type parent;
43                 public Type declaring_type;
44                 public String name;
45                 public MethodInfo get_method;
46                 public MethodInfo set_method;
47                 public PropertyAttributes attrs;
48                 
49                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
50                 internal static extern void get_property_info (MonoProperty prop, ref MonoPropertyInfo info,
51                                                                PInfo req_info);
52
53                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
54                 internal static extern Type[] GetTypeModifiers (MonoProperty prop, bool optional);
55
56                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
57                 internal static extern object get_default_value (MonoProperty prop);
58         }
59
60         [Flags]
61         internal enum PInfo {
62                 Attributes = 1,
63                 GetMethod  = 1 << 1,
64                 SetMethod  = 1 << 2,
65                 ReflectedType = 1 << 3,
66                 DeclaringType = 1 << 4,
67                 Name = 1 << 5
68                 
69         }
70
71         internal delegate object GetterAdapter (object _this);
72         internal delegate R Getter<T,R> (T _this);
73
74         [Serializable]
75         internal class MonoProperty : PropertyInfo, ISerializable {
76 #pragma warning disable 649
77                 internal IntPtr klass;
78                 internal IntPtr prop;
79                 MonoPropertyInfo info;
80                 PInfo cached;
81                 GetterAdapter cached_getter;
82
83 #pragma warning restore 649
84
85                 void CachePropertyInfo (PInfo flags)
86                 {
87                         if ((cached & flags) != flags) {
88                                 MonoPropertyInfo.get_property_info (this, ref info, flags);
89                                 cached |= flags;
90                         }
91                 }
92                 
93                 public override PropertyAttributes Attributes {
94                         get {
95                                 CachePropertyInfo (PInfo.Attributes);
96                                 return info.attrs;
97                         }
98                 }
99                 
100                 public override bool CanRead {
101                         get {
102                                 CachePropertyInfo (PInfo.GetMethod);
103                                 return (info.get_method != null);
104                         }
105                 }
106                 
107                 public override bool CanWrite {
108                         get {
109                                 CachePropertyInfo (PInfo.SetMethod);
110                                 return (info.set_method != null);
111                         }
112                 }
113
114                 public override Type PropertyType {
115                         get {
116                                 CachePropertyInfo (PInfo.GetMethod | PInfo.SetMethod);
117
118                                 if (info.get_method != null) {
119                                         return info.get_method.ReturnType;
120                                 } else {
121                                         ParameterInfo[] parameters = info.set_method.GetParameters ();
122                                         
123                                         return parameters [parameters.Length - 1].ParameterType;
124                                 }
125                         }
126                 }
127
128                 public override Type ReflectedType {
129                         get {
130                                 CachePropertyInfo (PInfo.ReflectedType);
131                                 return info.parent;
132                         }
133                 }
134                 
135                 public override Type DeclaringType {
136                         get {
137                                 CachePropertyInfo (PInfo.DeclaringType);
138                                 return info.declaring_type;
139                         }
140                 }
141                 
142                 public override string Name {
143                         get {
144                                 CachePropertyInfo (PInfo.Name);
145                                 return info.name;
146                         }
147                 }
148
149                 public override MethodInfo[] GetAccessors (bool nonPublic)
150                 {
151                         int nget = 0;
152                         int nset = 0;
153                         
154                         CachePropertyInfo (PInfo.GetMethod | PInfo.SetMethod);
155
156                         if (info.set_method != null && (nonPublic || info.set_method.IsPublic))
157                                 nset = 1;
158                         if (info.get_method != null && (nonPublic || info.get_method.IsPublic))
159                                 nget = 1;
160
161                         MethodInfo[] res = new MethodInfo [nget + nset];
162                         int n = 0;
163                         if (nset != 0)
164                                 res [n++] = info.set_method;
165                         if (nget != 0)
166                                 res [n++] = info.get_method;
167                         return res;
168                 }
169
170                 public override MethodInfo GetGetMethod (bool nonPublic)
171                 {
172                         CachePropertyInfo (PInfo.GetMethod);
173                         if (info.get_method != null && (nonPublic || info.get_method.IsPublic))
174                                 return info.get_method;
175                         else
176                                 return null;
177                 }
178
179                 public override ParameterInfo[] GetIndexParameters()
180                 {
181                         CachePropertyInfo (PInfo.GetMethod | PInfo.SetMethod);
182                         ParameterInfo[] res;
183                         if (info.get_method != null) {
184                                 res = info.get_method.GetParameters ();
185                         } else if (info.set_method != null) {
186                                 ParameterInfo[] src = info.set_method.GetParameters ();
187                                 res = new ParameterInfo [src.Length - 1];
188                                 Array.Copy (src, res, res.Length);
189                         } else
190                                 return new ParameterInfo [0];
191
192                         for (int i = 0; i < res.Length; ++i) {
193                                 ParameterInfo pinfo = res [i];
194                                 res [i] = new ParameterInfo (pinfo, this);
195                         }
196                         return res;     
197                 }
198                 
199                 public override MethodInfo GetSetMethod (bool nonPublic)
200                 {
201                         CachePropertyInfo (PInfo.SetMethod);
202                         if (info.set_method != null && (nonPublic || info.set_method.IsPublic))
203                                 return info.set_method;
204                         else
205                                 return null;
206                 }
207
208
209                 /*TODO verify for attribute based default values, just like ParameterInfo*/
210                 public override object GetConstantValue ()
211                 {
212                         return MonoPropertyInfo.get_default_value (this);
213                 }
214
215                 public override object GetRawConstantValue() {
216                         return MonoPropertyInfo.get_default_value (this);
217                 }
218
219                 // According to MSDN the inherit parameter is ignored here and
220                 // the behavior always defaults to inherit = false
221                 //
222                 public override bool IsDefined (Type attributeType, bool inherit)
223                 {
224                         return MonoCustomAttrs.IsDefined (this, attributeType, false);
225                 }
226
227                 public override object[] GetCustomAttributes (bool inherit)
228                 {
229                         return MonoCustomAttrs.GetCustomAttributes (this, false);
230                 }
231                 
232                 public override object[] GetCustomAttributes (Type attributeType, bool inherit)
233                 {
234                         return MonoCustomAttrs.GetCustomAttributes (this, attributeType, false);
235                 }
236
237
238                 delegate object GetterAdapter (object _this);
239                 delegate R Getter<T,R> (T _this);
240                 delegate R StaticGetter<R> ();
241
242 #pragma warning disable 169
243                 // Used via reflection
244                 static object GetterAdapterFrame<T,R> (Getter<T,R> getter, object obj)
245                 {
246                         return getter ((T)obj);
247                 }
248
249                 static object StaticGetterAdapterFrame<R> (StaticGetter<R> getter, object obj)
250                 {
251                         return getter ();
252                 }
253 #pragma warning restore 169
254
255                 /*
256                  * The idea behing this optimization is to use a pair of delegates to simulate the same effect of doing a reflection call.
257                  * The first delegate cast the this argument to the right type and the second does points to the target method.
258                  */
259                 static GetterAdapter CreateGetterDelegate (MethodInfo method)
260                 {
261                         Type[] typeVector;
262                         Type getterType;
263                         object getterDelegate;
264                         MethodInfo adapterFrame;
265                         Type getterDelegateType;
266                         string frameName;
267
268                         if (method.IsStatic) {
269                                 typeVector = new Type[] { method.ReturnType };
270                                 getterDelegateType = typeof (StaticGetter<>);
271                                 frameName = "StaticGetterAdapterFrame";
272                         } else {
273                                 typeVector = new Type[] { method.DeclaringType, method.ReturnType };
274                                 getterDelegateType = typeof (Getter<,>);
275                                 frameName = "GetterAdapterFrame";
276                         }
277
278                         getterType = getterDelegateType.MakeGenericType (typeVector);
279 #if NET_2_1
280                         // with Silverlight a coreclr failure (e.g. Transparent caller creating a delegate on a Critical method)
281                         // would normally throw an ArgumentException, so we set throwOnBindFailure to false and check for a null
282                         // delegate that we can transform into a MethodAccessException
283                         getterDelegate = Delegate.CreateDelegate (getterType, method, false);
284                         if (getterDelegate == null)
285                                 throw new MethodAccessException ();
286 #else
287                         getterDelegate = Delegate.CreateDelegate (getterType, method);
288 #endif
289                         adapterFrame = typeof (MonoProperty).GetMethod (frameName, BindingFlags.Static | BindingFlags.NonPublic);
290                         adapterFrame = adapterFrame.MakeGenericMethod (typeVector);
291                         return (GetterAdapter)Delegate.CreateDelegate (typeof (GetterAdapter), getterDelegate, adapterFrame, true);
292                 }
293                         
294                 public override object GetValue (object obj, object[] index)
295                 {
296                         if (index == null || index.Length == 0) {
297                                 /*FIXME we should check if the number of arguments matches the expected one, otherwise the error message will be pretty criptic.*/
298 #if !MONOTOUCH
299                                 if (cached_getter == null) {
300                                         if (!DeclaringType.IsValueType) { //FIXME find a way to build an invoke delegate for value types.
301                                                 MethodInfo method = GetGetMethod (true);
302                                                 if (method == null)
303                                                         throw new ArgumentException ("Get Method not found for '" + Name + "'");
304                                                 cached_getter = CreateGetterDelegate (method);
305                                                 return cached_getter (obj);
306                                         }
307                                 } else {
308                                         return cached_getter (obj);
309                                 }
310 #endif
311                         }
312
313                         return GetValue (obj, BindingFlags.Default, null, index, null);
314                 }
315
316                 public override object GetValue (object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)
317                 {
318                         object ret = null;
319
320                         MethodInfo method = GetGetMethod (true);
321                         if (method == null)
322                                 throw new ArgumentException ("Get Method not found for '" + Name + "'");
323
324                         try {
325                                 if (index == null || index.Length == 0) 
326                                         ret = method.Invoke (obj, invokeAttr, binder, null, culture);
327                                 else
328                                         ret = method.Invoke (obj, invokeAttr, binder, index, culture);
329                         }
330                         catch (SecurityException se) {
331                                 throw new TargetInvocationException (se);
332                         }
333
334                         return ret;
335                 }
336
337                 public override void SetValue (object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)
338                 {
339                         MethodInfo method = GetSetMethod (true);
340                         if (method == null)
341                                 throw new ArgumentException ("Set Method not found for '" + Name + "'");
342                         
343                         object [] parms;
344                         if (index == null || index.Length == 0) 
345                                 parms = new object [] {value};
346                         else {
347                                 int ilen = index.Length;
348                                 parms = new object [ilen+ 1];
349                                 index.CopyTo (parms, 0);
350                                 parms [ilen] = value;
351                         }
352
353                         method.Invoke (obj, invokeAttr, binder, parms, culture);
354                 }
355
356                 public override string ToString () {
357                         return PropertyType.ToString () + " " + Name;
358                 }
359
360                 public override Type[] GetOptionalCustomModifiers () {
361                         Type[] types = MonoPropertyInfo.GetTypeModifiers (this, true);
362                         if (types == null)
363                                 return Type.EmptyTypes;
364                         return types;
365                 }
366
367                 public override Type[] GetRequiredCustomModifiers () {
368                         Type[] types = MonoPropertyInfo.GetTypeModifiers (this, false);
369                         if (types == null)
370                                 return Type.EmptyTypes;
371                         return types;
372                 }
373
374                 // ISerializable
375                 public void GetObjectData (SerializationInfo info, StreamingContext context) 
376                 {
377                         MemberInfoSerializationHolder.Serialize (info, Name, ReflectedType,
378                                 ToString(), MemberTypes.Property);
379                 }
380
381 #if NET_4_0
382                 public override IList<CustomAttributeData> GetCustomAttributesData () {
383                         return CustomAttributeData.GetCustomAttributes (this);
384                 }
385 #endif
386         }
387 }