Add TimeZoneInfo Serialization
[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         [StructLayout (LayoutKind.Sequential)]
76         internal class MonoProperty : PropertyInfo, ISerializable {
77 #pragma warning disable 649
78                 internal IntPtr klass;
79                 internal IntPtr prop;
80                 MonoPropertyInfo info;
81                 PInfo cached;
82                 GetterAdapter cached_getter;
83
84 #pragma warning restore 649
85
86                 void CachePropertyInfo (PInfo flags)
87                 {
88                         if ((cached & flags) != flags) {
89                                 MonoPropertyInfo.get_property_info (this, ref info, flags);
90                                 cached |= flags;
91                         }
92                 }
93                 
94                 public override PropertyAttributes Attributes {
95                         get {
96                                 CachePropertyInfo (PInfo.Attributes);
97                                 return info.attrs;
98                         }
99                 }
100                 
101                 public override bool CanRead {
102                         get {
103                                 CachePropertyInfo (PInfo.GetMethod);
104                                 return (info.get_method != null);
105                         }
106                 }
107                 
108                 public override bool CanWrite {
109                         get {
110                                 CachePropertyInfo (PInfo.SetMethod);
111                                 return (info.set_method != null);
112                         }
113                 }
114
115                 public override Type PropertyType {
116                         get {
117                                 CachePropertyInfo (PInfo.GetMethod | PInfo.SetMethod);
118
119                                 if (info.get_method != null) {
120                                         return info.get_method.ReturnType;
121                                 } else {
122                                         ParameterInfo[] parameters = info.set_method.GetParametersInternal ();
123                                         
124                                         return parameters [parameters.Length - 1].ParameterType;
125                                 }
126                         }
127                 }
128
129                 public override Type ReflectedType {
130                         get {
131                                 CachePropertyInfo (PInfo.ReflectedType);
132                                 return info.parent;
133                         }
134                 }
135                 
136                 public override Type DeclaringType {
137                         get {
138                                 CachePropertyInfo (PInfo.DeclaringType);
139                                 return info.declaring_type;
140                         }
141                 }
142                 
143                 public override string Name {
144                         get {
145                                 CachePropertyInfo (PInfo.Name);
146                                 return info.name;
147                         }
148                 }
149
150                 public override MethodInfo[] GetAccessors (bool nonPublic)
151                 {
152                         int nget = 0;
153                         int nset = 0;
154                         
155                         CachePropertyInfo (PInfo.GetMethod | PInfo.SetMethod);
156
157                         if (info.set_method != null && (nonPublic || info.set_method.IsPublic))
158                                 nset = 1;
159                         if (info.get_method != null && (nonPublic || info.get_method.IsPublic))
160                                 nget = 1;
161
162                         MethodInfo[] res = new MethodInfo [nget + nset];
163                         int n = 0;
164                         if (nset != 0)
165                                 res [n++] = info.set_method;
166                         if (nget != 0)
167                                 res [n++] = info.get_method;
168                         return res;
169                 }
170
171                 public override MethodInfo GetGetMethod (bool nonPublic)
172                 {
173                         CachePropertyInfo (PInfo.GetMethod);
174                         if (info.get_method != null && (nonPublic || info.get_method.IsPublic))
175                                 return info.get_method;
176                         else
177                                 return null;
178                 }
179
180                 public override ParameterInfo[] GetIndexParameters()
181                 {
182                         CachePropertyInfo (PInfo.GetMethod | PInfo.SetMethod);
183                         ParameterInfo[] res;
184                         if (info.get_method != null) {
185                                 res = info.get_method.GetParameters ();
186                         } else if (info.set_method != null) {
187                                 ParameterInfo[] src = info.set_method.GetParametersInternal ();
188                                 res = new ParameterInfo [src.Length - 1];
189                                 Array.Copy (src, res, res.Length);
190                         } else
191                                 return EmptyArray<ParameterInfo>.Value;
192
193                         for (int i = 0; i < res.Length; ++i) {
194                                 ParameterInfo pinfo = res [i];
195                                 res [i] = new ParameterInfo (pinfo, this);
196                         }
197                         return res;     
198                 }
199                 
200                 public override MethodInfo GetSetMethod (bool nonPublic)
201                 {
202                         CachePropertyInfo (PInfo.SetMethod);
203                         if (info.set_method != null && (nonPublic || info.set_method.IsPublic))
204                                 return info.set_method;
205                         else
206                                 return null;
207                 }
208
209
210                 /*TODO verify for attribute based default values, just like ParameterInfo*/
211                 public override object GetConstantValue ()
212                 {
213                         return MonoPropertyInfo.get_default_value (this);
214                 }
215
216                 public override object GetRawConstantValue() {
217                         return MonoPropertyInfo.get_default_value (this);
218                 }
219
220                 // According to MSDN the inherit parameter is ignored here and
221                 // the behavior always defaults to inherit = false
222                 //
223                 public override bool IsDefined (Type attributeType, bool inherit)
224                 {
225                         return MonoCustomAttrs.IsDefined (this, attributeType, false);
226                 }
227
228                 public override object[] GetCustomAttributes (bool inherit)
229                 {
230                         return MonoCustomAttrs.GetCustomAttributes (this, false);
231                 }
232                 
233                 public override object[] GetCustomAttributes (Type attributeType, bool inherit)
234                 {
235                         return MonoCustomAttrs.GetCustomAttributes (this, attributeType, false);
236                 }
237
238
239                 delegate object GetterAdapter (object _this);
240                 delegate R Getter<T,R> (T _this);
241                 delegate R StaticGetter<R> ();
242
243 #pragma warning disable 169
244                 // Used via reflection
245                 static object GetterAdapterFrame<T,R> (Getter<T,R> getter, object obj)
246                 {
247                         return getter ((T)obj);
248                 }
249
250                 static object StaticGetterAdapterFrame<R> (StaticGetter<R> getter, object obj)
251                 {
252                         return getter ();
253                 }
254 #pragma warning restore 169
255
256                 /*
257                  * The idea behing this optimization is to use a pair of delegates to simulate the same effect of doing a reflection call.
258                  * The first delegate cast the this argument to the right type and the second does points to the target method.
259                  */
260                 static GetterAdapter CreateGetterDelegate (MethodInfo method)
261                 {
262                         Type[] typeVector;
263                         Type getterType;
264                         object getterDelegate;
265                         MethodInfo adapterFrame;
266                         Type getterDelegateType;
267                         string frameName;
268
269                         if (method.IsStatic) {
270                                 typeVector = new Type[] { method.ReturnType };
271                                 getterDelegateType = typeof (StaticGetter<>);
272                                 frameName = "StaticGetterAdapterFrame";
273                         } else {
274                                 typeVector = new Type[] { method.DeclaringType, method.ReturnType };
275                                 getterDelegateType = typeof (Getter<,>);
276                                 frameName = "GetterAdapterFrame";
277                         }
278
279                         getterType = getterDelegateType.MakeGenericType (typeVector);
280 #if NET_2_1
281                         // with Silverlight a coreclr failure (e.g. Transparent caller creating a delegate on a Critical method)
282                         // would normally throw an ArgumentException, so we set throwOnBindFailure to false and check for a null
283                         // delegate that we can transform into a MethodAccessException
284                         getterDelegate = Delegate.CreateDelegate (getterType, method, false);
285                         if (getterDelegate == null)
286                                 throw new MethodAccessException ();
287 #else
288                         getterDelegate = Delegate.CreateDelegate (getterType, method);
289 #endif
290                         adapterFrame = typeof (MonoProperty).GetMethod (frameName, BindingFlags.Static | BindingFlags.NonPublic);
291                         adapterFrame = adapterFrame.MakeGenericMethod (typeVector);
292                         return (GetterAdapter)Delegate.CreateDelegate (typeof (GetterAdapter), getterDelegate, adapterFrame, true);
293                 }
294                         
295                 public override object GetValue (object obj, object[] index)
296                 {
297                         if (index == null || index.Length == 0) {
298                                 /*FIXME we should check if the number of arguments matches the expected one, otherwise the error message will be pretty criptic.*/
299 #if !MONOTOUCH
300                                 if (cached_getter == null) {
301                                         MethodInfo method = GetGetMethod (true);
302                                         if (!DeclaringType.IsValueType && !method.ContainsGenericParameters) { //FIXME find a way to build an invoke delegate for value types.
303                                                 if (method == null)
304                                                         throw new ArgumentException ("Get Method not found for '" + Name + "'");
305                                                 cached_getter = CreateGetterDelegate (method);
306                                                 // The try-catch preserves the .Invoke () behaviour
307                                                 try {
308                                                         return cached_getter (obj);
309                                                 } catch (Exception ex) {
310                                                         throw new TargetInvocationException (ex);
311                                                 }
312                                         }
313                                 } else {
314                                         try {
315                                                 return cached_getter (obj);
316                                         } catch (Exception ex) {
317                                                 throw new TargetInvocationException (ex);
318                                         }
319                                 }
320 #endif
321                         }
322
323                         return GetValue (obj, BindingFlags.Default, null, index, null);
324                 }
325
326                 public override object GetValue (object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)
327                 {
328                         object ret = null;
329
330                         MethodInfo method = GetGetMethod (true);
331                         if (method == null)
332                                 throw new ArgumentException ("Get Method not found for '" + Name + "'");
333
334                         try {
335                                 if (index == null || index.Length == 0) 
336                                         ret = method.Invoke (obj, invokeAttr, binder, null, culture);
337                                 else
338                                         ret = method.Invoke (obj, invokeAttr, binder, index, culture);
339                         }
340                         catch (SecurityException se) {
341                                 throw new TargetInvocationException (se);
342                         }
343
344                         return ret;
345                 }
346
347                 public override void SetValue (object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)
348                 {
349                         MethodInfo method = GetSetMethod (true);
350                         if (method == null)
351                                 throw new ArgumentException ("Set Method not found for '" + Name + "'");
352                         
353                         object [] parms;
354                         if (index == null || index.Length == 0) 
355                                 parms = new object [] {value};
356                         else {
357                                 int ilen = index.Length;
358                                 parms = new object [ilen+ 1];
359                                 index.CopyTo (parms, 0);
360                                 parms [ilen] = value;
361                         }
362
363                         method.Invoke (obj, invokeAttr, binder, parms, culture);
364                 }
365
366                 public override string ToString () {
367                         return PropertyType.ToString () + " " + Name;
368                 }
369
370                 public override Type[] GetOptionalCustomModifiers () {
371                         Type[] types = MonoPropertyInfo.GetTypeModifiers (this, true);
372                         if (types == null)
373                                 return Type.EmptyTypes;
374                         return types;
375                 }
376
377                 public override Type[] GetRequiredCustomModifiers () {
378                         Type[] types = MonoPropertyInfo.GetTypeModifiers (this, false);
379                         if (types == null)
380                                 return Type.EmptyTypes;
381                         return types;
382                 }
383
384                 // ISerializable
385                 public void GetObjectData (SerializationInfo info, StreamingContext context) 
386                 {
387                         MemberInfoSerializationHolder.Serialize (info, Name, ReflectedType,
388                                 ToString(), MemberTypes.Property);
389                 }
390
391 #if NET_4_0
392                 public override IList<CustomAttributeData> GetCustomAttributesData () {
393                         return CustomAttributeData.GetCustomAttributes (this);
394                 }
395 #endif
396         }
397 }