+
+ delegate object GetterAdapter (object _this);
+ delegate R Getter<T,R> (T _this);
+ delegate R StaticGetter<R> ();
+
+#pragma warning disable 169
+ // Used via reflection
+ static object GetterAdapterFrame<T,R> (Getter<T,R> getter, object obj)
+ {
+ return getter ((T)obj);
+ }
+
+ static object StaticGetterAdapterFrame<R> (StaticGetter<R> getter, object obj)
+ {
+ return getter ();
+ }
+#pragma warning restore 169
+
+ /*
+ * The idea behing this optimization is to use a pair of delegates to simulate the same effect of doing a reflection call.
+ * The first delegate cast the this argument to the right type and the second does points to the target method.
+ */
+ static GetterAdapter CreateGetterDelegate (MethodInfo method)
+ {
+ Type[] typeVector;
+ Type getterType;
+ object getterDelegate;
+ MethodInfo adapterFrame;
+ Type getterDelegateType;
+ string frameName;
+
+ if (method.IsStatic) {
+ typeVector = new Type[] { method.ReturnType };
+ getterDelegateType = typeof (StaticGetter<>);
+ frameName = "StaticGetterAdapterFrame";
+ } else {
+ typeVector = new Type[] { method.DeclaringType, method.ReturnType };
+ getterDelegateType = typeof (Getter<,>);
+ frameName = "GetterAdapterFrame";
+ }
+
+ getterType = getterDelegateType.MakeGenericType (typeVector);
+#if NET_2_1
+ // with Silverlight a coreclr failure (e.g. Transparent caller creating a delegate on a Critical method)
+ // would normally throw an ArgumentException, so we set throwOnBindFailure to false and check for a null
+ // delegate that we can transform into a MethodAccessException
+ getterDelegate = Delegate.CreateDelegate (getterType, method, false);
+ if (getterDelegate == null)
+ throw new MethodAccessException ();
+#else
+ getterDelegate = Delegate.CreateDelegate (getterType, method);
+#endif
+ adapterFrame = typeof (MonoProperty).GetMethod (frameName, BindingFlags.Static | BindingFlags.NonPublic);
+ adapterFrame = adapterFrame.MakeGenericMethod (typeVector);
+ return (GetterAdapter)Delegate.CreateDelegate (typeof (GetterAdapter), getterDelegate, adapterFrame, true);
+ }
+
+ public override object GetValue (object obj, object[] index)
+ {
+ if (index == null || index.Length == 0) {
+ /*FIXME we should check if the number of arguments matches the expected one, otherwise the error message will be pretty criptic.*/
+#if !MONOTOUCH
+ if (cached_getter == null) {
+ if (!DeclaringType.IsValueType) { //FIXME find a way to build an invoke delegate for value types.
+ MethodInfo method = GetGetMethod (true);
+ if (method == null)
+ throw new ArgumentException ("Get Method not found for '" + Name + "'");
+ cached_getter = CreateGetterDelegate (method);
+ return cached_getter (obj);
+ }
+ } else {
+ return cached_getter (obj);
+ }
+#endif
+ }
+
+ return GetValue (obj, BindingFlags.Default, null, index, null);
+ }
+