File: system\runtime\interopservices\windowsruntime\custompropertyimpl.cs
Project: ndp\clr\src\bcl\mscorlib.csproj (mscorlib)
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
//
// <OWNER>Microsoft</OWNER>
 
using System;
using System.Security;
using System.Reflection;
using System.Diagnostics.Contracts;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.StubHelpers;
using System.Globalization;
 
namespace System.Runtime.InteropServices.WindowsRuntime
{
    //
    // ICustomProperty implementation - basically a wrapper of PropertyInfo
    //
    internal sealed class CustomPropertyImpl : ICustomProperty
    {     
        private PropertyInfo  m_property;
 
        //
        // Constructor
        //
        public CustomPropertyImpl(PropertyInfo propertyInfo)
        {
            if (propertyInfo == null)
                throw new ArgumentNullException("propertyInfo");
 
            m_property = propertyInfo;
        }
 
        //
        // ICustomProperty interface implementation
        //
 
        public string Name
        {
            get
            {
                return m_property.Name;
            }
        }
        
        public bool CanRead
        {
            get 
            { 
                // Return false if the getter is not public
                return m_property.GetGetMethod() != null;
            }
        }
 
        public bool CanWrite
        {
            get 
            {
                // Return false if the setter is not public
                return m_property.GetSetMethod() != null;
            }
        }
 
        public object GetValue(object target)
        {
            return InvokeInternal(target, null, true);
        }
 
        // Unlike normal .Net, Jupiter properties can have at most one indexer parameter. A null
        // indexValue here means that the property has an indexer argument and its value is null.
        public object GetValue(object target, object indexValue)
        {
            return InvokeInternal(target, new object[] { indexValue }, true);
        }
 
        public void SetValue(object target, object value)
        {
            InvokeInternal(target, new object[] { value }, false);
        }
 
        // Unlike normal .Net, Jupiter properties can have at most one indexer parameter. A null
        // indexValue here means that the property has an indexer argument and its value is null.
        public void SetValue(object target, object value, object indexValue)
        {
            InvokeInternal(target, new object[] { indexValue, value }, false);
        }
 
        [SecuritySafeCritical]
        private object InvokeInternal(object target, object[] args, bool getValue)
        {
            // Forward to the right object if we are dealing with a proxy
            IGetProxyTarget proxy = target as IGetProxyTarget;
            if (proxy != null)
            {
                target = proxy.GetTarget();
            }
 
            // You can get PropertyInfo for properties with a private getter/public setter (or vice versa) 
            // even if you pass BindingFlags.Public only. And in this case, passing binding flags to 
            // GetValue/SetValue won't work as the default binder ignores those values
            // Use GetGetMethod/GetSetMethod instead
 
            // We get non-public accessors just so that we can throw the correct exception.
            MethodInfo accessor = getValue ? m_property.GetGetMethod(true) : m_property.GetSetMethod(true);
            
            if (accessor == null)
                throw new ArgumentException(System.Environment.GetResourceString(getValue ? "Arg_GetMethNotFnd" : "Arg_SetMethNotFnd"));
 
            if (!accessor.IsPublic)
                throw new MethodAccessException(
                    String.Format(
                        CultureInfo.CurrentCulture,
                        Environment.GetResourceString("Arg_MethodAccessException_WithMethodName"),
                        accessor.ToString(),
                        accessor.DeclaringType.FullName));
 
            RuntimeMethodInfo rtMethod = accessor as RuntimeMethodInfo;
            if (rtMethod == null)
                throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeMethodInfo"));
 
            // We can safely skip access check because this is only used in full trust scenarios.
            // And we have already verified that the property accessor is public.
            Contract.Assert(AppDomain.CurrentDomain.PermissionSet.IsUnrestricted());
            return rtMethod.UnsafeInvoke(target, BindingFlags.Default, null, args, null);
        }
 
        public Type Type
        {
            get
            {
                return m_property.PropertyType;
            }
        }
    }
}