1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
6 using System.Reflection;
8 namespace System.Runtime.InteropServices.WindowsRuntime
11 // ICustomProperty implementation - basically a wrapper of PropertyInfo
13 internal sealed class CustomPropertyImpl : ICustomProperty
15 private PropertyInfo m_property;
20 public CustomPropertyImpl(PropertyInfo propertyInfo)
22 if (propertyInfo == null)
23 throw new ArgumentNullException(nameof(propertyInfo));
25 m_property = propertyInfo;
29 // ICustomProperty interface implementation
36 return m_property.Name;
44 // Return false if the getter is not public
45 return m_property.GetGetMethod() != null;
53 // Return false if the setter is not public
54 return m_property.GetSetMethod() != null;
58 public object GetValue(object target)
60 return InvokeInternal(target, null, true);
63 // Unlike normal .Net, Jupiter properties can have at most one indexer parameter. A null
64 // indexValue here means that the property has an indexer argument and its value is null.
65 public object GetValue(object target, object indexValue)
67 return InvokeInternal(target, new object[] { indexValue }, true);
70 public void SetValue(object target, object value)
72 InvokeInternal(target, new object[] { value }, false);
75 // Unlike normal .Net, Jupiter properties can have at most one indexer parameter. A null
76 // indexValue here means that the property has an indexer argument and its value is null.
77 public void SetValue(object target, object value, object indexValue)
79 InvokeInternal(target, new object[] { indexValue, value }, false);
82 private object InvokeInternal(object target, object[]? args, bool getValue)
84 // Forward to the right object if we are dealing with a proxy
85 if (target is IGetProxyTarget proxy)
87 target = proxy.GetTarget();
90 // You can get PropertyInfo for properties with a private getter/public setter (or vice versa)
91 // even if you pass BindingFlags.Public only. And in this case, passing binding flags to
92 // GetValue/SetValue won't work as the default binder ignores those values
93 // Use GetGetMethod/GetSetMethod instead
95 // We get non-public accessors just so that we can throw the correct exception.
96 MethodInfo accessor = getValue ? m_property.GetGetMethod(true) : m_property.GetSetMethod(true);
99 throw new ArgumentException(getValue ? SR.Arg_GetMethNotFnd : SR.Arg_SetMethNotFnd);
101 if (!accessor.IsPublic)
102 throw new MethodAccessException(
104 SR.Arg_MethodAccessException_WithMethodName,
106 accessor.DeclaringType.FullName));
108 RuntimeMethodInfo? rtMethod = accessor as RuntimeMethodInfo;
109 if (rtMethod == null)
110 throw new ArgumentException(SR.Argument_MustBeRuntimeMethodInfo);
112 // We can safely skip access check because this is only used in full trust scenarios.
113 // And we have already verified that the property accessor is public.
114 return rtMethod.Invoke(target, BindingFlags.Default, null, args, null);
121 return m_property.PropertyType;