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.
5 using System.Collections.Generic;
6 using System.Diagnostics;
7 using System.Globalization;
9 using RuntimeTypeCache = System.RuntimeType.RuntimeTypeCache;
11 namespace System.Reflection
13 internal unsafe sealed class RuntimePropertyInfo : PropertyInfo
15 #region Private Data Members
17 private string m_name;
18 private void* m_utf8name;
19 private PropertyAttributes m_flags;
20 private RuntimeTypeCache m_reflectedTypeCache;
21 private RuntimeMethodInfo m_getterMethod;
22 private RuntimeMethodInfo m_setterMethod;
23 private MethodInfo[] m_otherMethod;
24 private RuntimeType m_declaringType;
25 private BindingFlags m_bindingFlags;
26 private Signature m_signature;
27 private ParameterInfo[] m_parameters;
31 internal RuntimePropertyInfo(
32 int tkProperty, RuntimeType declaredType, RuntimeTypeCache reflectedTypeCache, out bool isPrivate)
34 Debug.Assert(declaredType != null);
35 Debug.Assert(reflectedTypeCache != null);
36 Debug.Assert(!reflectedTypeCache.IsGlobal);
38 MetadataImport scope = declaredType.GetRuntimeModule().MetadataImport;
41 m_reflectedTypeCache = reflectedTypeCache;
42 m_declaringType = declaredType;
45 scope.GetPropertyProps(tkProperty, out m_utf8name, out m_flags, out sig);
47 RuntimeMethodInfo dummy;
48 Associates.AssignAssociates(scope, tkProperty, declaredType, reflectedTypeCache.GetRuntimeType(),
49 out dummy, out dummy, out dummy,
50 out m_getterMethod, out m_setterMethod, out m_otherMethod,
51 out isPrivate, out m_bindingFlags);
55 #region Internal Members
56 internal override bool CacheEquals(object o)
58 RuntimePropertyInfo m = o as RuntimePropertyInfo;
60 if ((object)m == null)
63 return m.m_token == m_token &&
64 RuntimeTypeHandle.GetModule(m_declaringType).Equals(
65 RuntimeTypeHandle.GetModule(m.m_declaringType));
68 internal Signature Signature
72 if (m_signature == null)
74 PropertyAttributes flags;
78 GetRuntimeModule().MetadataImport.GetPropertyProps(
79 m_token, out name, out flags, out sig);
81 m_signature = new Signature(sig.Signature.ToPointer(), (int)sig.Length, m_declaringType);
87 internal bool EqualsSig(RuntimePropertyInfo target)
89 //@Asymmetry - Legacy policy is to remove duplicate properties, including hidden properties.
90 // The comparison is done by name and by sig. The EqualsSig comparison is expensive
91 // but forutnetly it is only called when an inherited property is hidden by name or
92 // when an interfaces declare properies with the same signature.
93 // Note that we intentionally don't resolve generic arguments so that we don't treat
94 // signatures that only match in certain instantiations as duplicates. This has the
95 // down side of treating overriding and overriden properties as different properties
96 // in some cases. But PopulateProperties in rttype.cs should have taken care of that
97 // by comparing VTable slots.
100 // Property Prop1(ByVal t1 As T) As Integer
105 // Property Prop1(ByVal y1 As Y) As Integer
113 Debug.Assert(Name.Equals(target.Name));
114 Debug.Assert(this != target);
115 Debug.Assert(this.ReflectedType == target.ReflectedType);
117 return Signature.CompareSig(this.Signature, target.Signature);
119 internal BindingFlags BindingFlags { get { return m_bindingFlags; } }
122 #region Object Overrides
123 public override string ToString()
125 var sbName = new ValueStringBuilder(MethodBase.MethodNameBufferSize);
127 sbName.Append(PropertyType.FormatTypeName());
131 RuntimeType[] arguments = Signature.Arguments;
132 if (arguments.Length > 0)
135 MethodBase.AppendParameters(ref sbName, arguments, Signature.CallingConvention);
139 return sbName.ToString();
143 #region ICustomAttributeProvider
144 public override object[] GetCustomAttributes(bool inherit)
146 return CustomAttribute.GetCustomAttributes(this, typeof(object) as RuntimeType);
149 public override object[] GetCustomAttributes(Type attributeType, bool inherit)
151 if (attributeType == null)
152 throw new ArgumentNullException(nameof(attributeType));
154 RuntimeType attributeRuntimeType = attributeType.UnderlyingSystemType as RuntimeType;
156 if (attributeRuntimeType == null)
157 throw new ArgumentException(SR.Arg_MustBeType, nameof(attributeType));
159 return CustomAttribute.GetCustomAttributes(this, attributeRuntimeType);
162 public override bool IsDefined(Type attributeType, bool inherit)
164 if (attributeType == null)
165 throw new ArgumentNullException(nameof(attributeType));
167 RuntimeType attributeRuntimeType = attributeType.UnderlyingSystemType as RuntimeType;
169 if (attributeRuntimeType == null)
170 throw new ArgumentException(SR.Arg_MustBeType, nameof(attributeType));
172 return CustomAttribute.IsDefined(this, attributeRuntimeType);
175 public override IList<CustomAttributeData> GetCustomAttributesData()
177 return CustomAttributeData.GetCustomAttributesInternal(this);
181 #region MemberInfo Overrides
182 public override MemberTypes MemberType { get { return MemberTypes.Property; } }
183 public override string Name
188 m_name = new MdUtf8String(m_utf8name).ToString();
193 public override Type DeclaringType
197 return m_declaringType;
201 public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) => HasSameMetadataDefinitionAsCore<RuntimePropertyInfo>(other);
203 public override Type ReflectedType
207 return ReflectedTypeInternal;
211 private RuntimeType ReflectedTypeInternal
215 return m_reflectedTypeCache.GetRuntimeType();
219 public override int MetadataToken { get { return m_token; } }
221 public override Module Module { get { return GetRuntimeModule(); } }
222 internal RuntimeModule GetRuntimeModule() { return m_declaringType.GetRuntimeModule(); }
223 public override bool IsCollectible => m_declaringType.IsCollectible;
226 #region PropertyInfo Overrides
230 public override Type[] GetRequiredCustomModifiers()
232 return Signature.GetCustomModifiers(0, true);
235 public override Type[] GetOptionalCustomModifiers()
237 return Signature.GetCustomModifiers(0, false);
240 internal object GetConstantValue(bool raw)
242 object defaultValue = MdConstant.GetValue(GetRuntimeModule().MetadataImport, m_token, PropertyType.GetTypeHandleInternal(), raw);
244 if (defaultValue == DBNull.Value)
245 // Arg_EnumLitValueNotFound -> "Literal value was not found."
246 throw new InvalidOperationException(SR.Arg_EnumLitValueNotFound);
251 public override object GetConstantValue() { return GetConstantValue(false); }
253 public override object GetRawConstantValue() { return GetConstantValue(true); }
255 public override MethodInfo[] GetAccessors(bool nonPublic)
257 List<MethodInfo> accessorList = new List<MethodInfo>();
259 if (Associates.IncludeAccessor(m_getterMethod, nonPublic))
260 accessorList.Add(m_getterMethod);
262 if (Associates.IncludeAccessor(m_setterMethod, nonPublic))
263 accessorList.Add(m_setterMethod);
265 if ((object)m_otherMethod != null)
267 for (int i = 0; i < m_otherMethod.Length; i++)
269 if (Associates.IncludeAccessor(m_otherMethod[i] as MethodInfo, nonPublic))
270 accessorList.Add(m_otherMethod[i]);
273 return accessorList.ToArray();
276 public override Type PropertyType
278 get { return Signature.ReturnType; }
281 public override MethodInfo GetGetMethod(bool nonPublic)
283 if (!Associates.IncludeAccessor(m_getterMethod, nonPublic))
286 return m_getterMethod;
289 public override MethodInfo GetSetMethod(bool nonPublic)
291 if (!Associates.IncludeAccessor(m_setterMethod, nonPublic))
294 return m_setterMethod;
297 public override ParameterInfo[] GetIndexParameters()
299 ParameterInfo[] indexParams = GetIndexParametersNoCopy();
301 int numParams = indexParams.Length;
306 ParameterInfo[] ret = new ParameterInfo[numParams];
308 Array.Copy(indexParams, ret, numParams);
313 internal ParameterInfo[] GetIndexParametersNoCopy()
315 // @History - Logic ported from RTM
317 // No need to lock because we don't guarantee the uniqueness of ParameterInfo objects
318 if (m_parameters == null)
321 ParameterInfo[] methParams = null;
323 // First try to get the Get method.
324 MethodInfo m = GetGetMethod(true);
327 // There is a Get method so use it.
328 methParams = m.GetParametersNoCopy();
329 numParams = methParams.Length;
333 // If there is no Get method then use the Set method.
334 m = GetSetMethod(true);
338 methParams = m.GetParametersNoCopy();
339 numParams = methParams.Length - 1;
343 // Now copy over the parameter info's and change their
344 // owning member info to the current property info.
346 ParameterInfo[] propParams = new ParameterInfo[numParams];
348 for (int i = 0; i < numParams; i++)
349 propParams[i] = new RuntimeParameterInfo((RuntimeParameterInfo)methParams[i], this);
351 m_parameters = propParams;
357 public override PropertyAttributes Attributes
365 public override bool CanRead
369 return m_getterMethod != null;
373 public override bool CanWrite
377 return m_setterMethod != null;
383 [DebuggerStepThroughAttribute]
384 [Diagnostics.DebuggerHidden]
385 public override object GetValue(object obj, object[] index)
387 return GetValue(obj, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static,
391 [DebuggerStepThroughAttribute]
392 [Diagnostics.DebuggerHidden]
393 public override object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)
395 MethodInfo m = GetGetMethod(true);
397 throw new ArgumentException(System.SR.Arg_GetMethNotFnd);
398 return m.Invoke(obj, invokeAttr, binder, index, null);
401 [DebuggerStepThroughAttribute]
402 [Diagnostics.DebuggerHidden]
403 public override void SetValue(object obj, object value, object[] index)
407 BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static,
413 [DebuggerStepThroughAttribute]
414 [Diagnostics.DebuggerHidden]
415 public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)
417 MethodInfo m = GetSetMethod(true);
420 throw new ArgumentException(System.SR.Arg_SetMethNotFnd);
422 object[] args = null;
426 args = new object[index.Length + 1];
428 for (int i = 0; i < index.Length; i++)
431 args[index.Length] = value;
435 args = new object[1];
439 m.Invoke(obj, invokeAttr, binder, args, culture);