2009-10-20 Sebastien Pouliot <sebastien@ximian.com>
[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.Globalization;
33 using System.Runtime.CompilerServices;
34 using System.Runtime.InteropServices;
35 using System.Runtime.Serialization;
36 using System.Security;
37
38 namespace System.Reflection {
39         
40         internal struct MonoPropertyInfo {
41                 public Type parent;
42                 public String name;
43                 public MethodInfo get_method;
44                 public MethodInfo set_method;
45                 public PropertyAttributes attrs;
46                 
47                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
48                 internal static extern void get_property_info (MonoProperty prop, ref MonoPropertyInfo info,
49                                                                PInfo req_info);
50
51                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
52                 internal static extern Type[] GetTypeModifiers (MonoProperty prop, bool optional);
53
54         }
55
56         [Flags]
57         internal enum PInfo {
58                 Attributes = 1,
59                 GetMethod  = 1 << 1,
60                 SetMethod  = 1 << 2,
61                 ReflectedType = 1 << 3,
62                 DeclaringType = 1 << 4,
63                 Name = 1 << 5
64                 
65         }
66
67 #if NET_2_0
68         internal delegate object GetterAdapter (object _this);
69         internal delegate R Getter<T,R> (T _this);
70 #endif
71
72         [Serializable]
73         internal class MonoProperty : PropertyInfo, ISerializable {
74 #pragma warning disable 649
75                 internal IntPtr klass;
76                 internal IntPtr prop;
77                 MonoPropertyInfo info;
78                 PInfo cached;
79 #if NET_2_0
80                 GetterAdapter cached_getter;
81 #endif
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.parent;
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);
182                         if (info.get_method != null)
183                                 return info.get_method.GetParameters ();
184                         return new ParameterInfo [0];
185                 }
186                 
187                 public override MethodInfo GetSetMethod (bool nonPublic)
188                 {
189                         CachePropertyInfo (PInfo.SetMethod);
190                         if (info.set_method != null && (nonPublic || info.set_method.IsPublic))
191                                 return info.set_method;
192                         else
193                                 return null;
194                 }
195
196                 // According to MSDN the inherit parameter is ignored here and
197                 // the behavior always defaults to inherit = false
198                 //
199                 public override bool IsDefined (Type attributeType, bool inherit)
200                 {
201                         return MonoCustomAttrs.IsDefined (this, attributeType, false);
202                 }
203
204                 public override object[] GetCustomAttributes (bool inherit)
205                 {
206                         return MonoCustomAttrs.GetCustomAttributes (this, false);
207                 }
208                 
209                 public override object[] GetCustomAttributes (Type attributeType, bool inherit)
210                 {
211                         return MonoCustomAttrs.GetCustomAttributes (this, attributeType, false);
212                 }
213
214
215 #if NET_2_0
216                 delegate object GetterAdapter (object _this);
217                 delegate R Getter<T,R> (T _this);
218                 delegate R StaticGetter<R> ();
219
220                 static object GetterAdapterFrame<T,R> (Getter<T,R> getter, object obj)
221                 {
222                         return getter ((T)obj);
223                 }
224
225                 static object StaticGetterAdapterFrame<R> (StaticGetter<R> getter, object obj)
226                 {
227                         return getter ();
228                 }
229
230                 /*
231                  * The idea behing this optimization is to use a pair of delegates to simulate the same effect of doing a reflection call.
232                  * The first delegate cast the this argument to the right type and the second does points to the target method.
233                  */
234                 static GetterAdapter CreateGetterDelegate (MethodInfo method)
235                 {
236                         Type[] typeVector;
237                         Type getterType;
238                         object getterDelegate;
239                         MethodInfo adapterFrame;
240                         Type getterDelegateType;
241                         string frameName;
242
243                         if (method.IsStatic) {
244                                 typeVector = new Type[] { method.ReturnType };
245                                 getterDelegateType = typeof (StaticGetter<>);
246                                 frameName = "StaticGetterAdapterFrame";
247                         } else {
248                                 typeVector = new Type[] { method.DeclaringType, method.ReturnType };
249                                 getterDelegateType = typeof (Getter<,>);
250                                 frameName = "GetterAdapterFrame";
251                         }
252
253                         getterType = getterDelegateType.MakeGenericType (typeVector);
254 #if NET_2_1
255                         // with Silverlight a coreclr failure (e.g. Transparent caller creating a delegate on a Critical method)
256                         // would normally throw an ArgumentException, so we set throwOnBindFailure to false and check for a null
257                         // delegate that we can transform into a MethodAccessException
258                         getterDelegate = Delegate.CreateDelegate (getterType, method, false);
259                         if (getterDelegate == null)
260                                 throw new MethodAccessException ();
261 #else
262                         getterDelegate = Delegate.CreateDelegate (getterType, method);
263 #endif
264                         adapterFrame = typeof (MonoProperty).GetMethod (frameName, BindingFlags.Static | BindingFlags.NonPublic);
265                         adapterFrame = adapterFrame.MakeGenericMethod (typeVector);
266                         return (GetterAdapter)Delegate.CreateDelegate (typeof (GetterAdapter), getterDelegate, adapterFrame, true);
267                 }
268                         
269                 public override object GetValue (object obj, object[] index)
270                 {
271                         if (index == null || index.Length == 0) {
272                                 /*FIXME we should check if the number of arguments matches the expected one, otherwise the error message will be pretty criptic.*/
273 #if !MONOTOUCH
274                                 if (cached_getter == null) {
275                                         if (!DeclaringType.IsValueType) { //FIXME find a way to build an invoke delegate for value types.
276                                                 MethodInfo method = GetGetMethod (true);
277                                                 if (method == null)
278                                                         throw new ArgumentException ("Get Method not found for '" + Name + "'");
279                                                 cached_getter = CreateGetterDelegate (method);
280                                                 return cached_getter (obj);
281                                         }
282                                 } else {
283                                         return cached_getter (obj);
284                                 }
285 #endif
286                         }
287
288                         return GetValue (obj, BindingFlags.Default, null, index, null);
289                 }
290 #endif
291
292                 public override object GetValue (object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)
293                 {
294                         object ret = null;
295
296                         MethodInfo method = GetGetMethod (true);
297                         if (method == null)
298                                 throw new ArgumentException ("Get Method not found for '" + Name + "'");
299
300                         try {
301                                 if (index == null || index.Length == 0) 
302                                         ret = method.Invoke (obj, invokeAttr, binder, null, culture);
303                                 else
304                                         ret = method.Invoke (obj, invokeAttr, binder, index, culture);
305                         }
306                         catch (SecurityException se) {
307                                 throw new TargetInvocationException (se);
308                         }
309
310                         return ret;
311                 }
312
313                 public override void SetValue (object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)
314                 {
315                         MethodInfo method = GetSetMethod (true);
316                         if (method == null)
317                                 throw new ArgumentException ("Set Method not found for '" + Name + "'");
318                         
319                         object [] parms;
320                         if (index == null || index.Length == 0) 
321                                 parms = new object [] {value};
322                         else {
323                                 int ilen = index.Length;
324                                 parms = new object [ilen+ 1];
325                                 index.CopyTo (parms, 0);
326                                 parms [ilen] = value;
327                         }
328
329                         method.Invoke (obj, invokeAttr, binder, parms, culture);
330                 }
331
332                 public override string ToString () {
333                         return PropertyType.ToString () + " " + Name;
334                 }
335
336 #if NET_2_0 || BOOTSTRAP_NET_2_0
337
338                 public override Type[] GetOptionalCustomModifiers () {
339                         Type[] types = MonoPropertyInfo.GetTypeModifiers (this, true);
340                         if (types == null)
341                                 return Type.EmptyTypes;
342                         return types;
343                 }
344
345                 public override Type[] GetRequiredCustomModifiers () {
346                         Type[] types = MonoPropertyInfo.GetTypeModifiers (this, false);
347                         if (types == null)
348                                 return Type.EmptyTypes;
349                         return types;
350                 }
351 #endif
352
353                 // ISerializable
354                 public void GetObjectData (SerializationInfo info, StreamingContext context) 
355                 {
356                         MemberInfoSerializationHolder.Serialize (info, Name, ReflectedType,
357                                 ToString(), MemberTypes.Property);
358                 }
359         }
360 }