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. 4 5 using System; 6 using System.Text; 7 using System.Reflection; 8 using System.Diagnostics; 9 using System.Globalization; 10 using System.Collections.Generic; 11 using System.Runtime.CompilerServices; 12 using System.Reflection.Runtime.General; 13 using System.Reflection.Runtime.TypeInfos; 14 using System.Reflection.Runtime.MethodInfos; 15 using System.Reflection.Runtime.ParameterInfos; 16 using System.Reflection.Runtime.CustomAttributes; 17 18 using Internal.Reflection.Core; 19 using Internal.Reflection.Core.Execution; 20 21 using Internal.Reflection.Tracing; 22 23 24 namespace System.Reflection.Runtime.PropertyInfos 25 { 26 // 27 // The runtime's implementation of PropertyInfo's 28 // 29 [DebuggerDisplay("{_debugName}")] 30 internal abstract partial class RuntimePropertyInfo : PropertyInfo, ITraceableTypeMember 31 { 32 // 33 // propertyHandle - the "tkPropertyDef" that identifies the property. 34 // definingType - the "tkTypeDef" that defined the field (this is where you get the metadata reader that created propertyHandle.) 35 // contextType - the type that supplies the type context (i.e. substitutions for generic parameters.) Though you 36 // get your raw information from "definingType", you report "contextType" as your DeclaringType property. 37 // 38 // For example: 39 // 40 // typeof(Foo<>).GetTypeInfo().DeclaredMembers 41 // 42 // The definingType and contextType are both Foo<> 43 // 44 // typeof(Foo<int,String>).GetTypeInfo().DeclaredMembers 45 // 46 // The definingType is "Foo<,>" 47 // The contextType is "Foo<int,String>" 48 // 49 // We don't report any DeclaredMembers for arrays or generic parameters so those don't apply. 50 // RuntimePropertyInfo(RuntimeTypeInfo contextTypeInfo, RuntimeTypeInfo reflectedType)51 protected RuntimePropertyInfo(RuntimeTypeInfo contextTypeInfo, RuntimeTypeInfo reflectedType) 52 { 53 ContextTypeInfo = contextTypeInfo; 54 _reflectedType = reflectedType; 55 } 56 57 public sealed override bool CanRead 58 { 59 get 60 { 61 return Getter != null; 62 } 63 } 64 65 public sealed override bool CanWrite 66 { 67 get 68 { 69 return Setter != null; 70 } 71 } 72 73 public sealed override Type DeclaringType 74 { 75 get 76 { 77 #if ENABLE_REFLECTION_TRACE 78 if (ReflectionTrace.Enabled) 79 ReflectionTrace.PropertyInfo_DeclaringType(this); 80 #endif 81 82 return ContextTypeInfo; 83 } 84 } 85 GetIndexParameters()86 public sealed override ParameterInfo[] GetIndexParameters() 87 { 88 ParameterInfo[] indexParameters = _lazyIndexParameters; 89 if (indexParameters == null) 90 { 91 bool useGetter = CanRead; 92 RuntimeMethodInfo accessor = (useGetter ? Getter : Setter); 93 RuntimeParameterInfo[] runtimeMethodParameterInfos = accessor.RuntimeParameters; 94 int count = runtimeMethodParameterInfos.Length; 95 if (!useGetter) 96 count--; // If we're taking the parameters off the setter, subtract one for the "value" parameter. 97 if (count == 0) 98 { 99 _lazyIndexParameters = indexParameters = Array.Empty<ParameterInfo>(); 100 } 101 else 102 { 103 indexParameters = new ParameterInfo[count]; 104 for (int i = 0; i < count; i++) 105 { 106 indexParameters[i] = RuntimePropertyIndexParameterInfo.GetRuntimePropertyIndexParameterInfo(this, runtimeMethodParameterInfos[i]); 107 } 108 _lazyIndexParameters = indexParameters; 109 } 110 } 111 112 int numParameters = indexParameters.Length; 113 if (numParameters == 0) 114 return indexParameters; 115 ParameterInfo[] result = new ParameterInfo[numParameters]; 116 for (int i = 0; i < numParameters; i++) 117 { 118 result[i] = indexParameters[i]; 119 } 120 return result; 121 } 122 123 public sealed override MethodInfo GetMethod 124 { 125 get 126 { 127 #if ENABLE_REFLECTION_TRACE 128 if (ReflectionTrace.Enabled) 129 ReflectionTrace.PropertyInfo_GetMethod(this); 130 #endif 131 132 return Getter; 133 } 134 } 135 GetOptionalCustomModifiers()136 public sealed override Type[] GetOptionalCustomModifiers() => PropertyTypeHandle.GetCustomModifiers(ContextTypeInfo.TypeContext, optional: true); 137 GetRequiredCustomModifiers()138 public sealed override Type[] GetRequiredCustomModifiers() => PropertyTypeHandle.GetCustomModifiers(ContextTypeInfo.TypeContext, optional: false); 139 GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)140 public sealed override object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture) 141 { 142 #if ENABLE_REFLECTION_TRACE 143 if (ReflectionTrace.Enabled) 144 ReflectionTrace.PropertyInfo_GetValue(this, obj, index); 145 #endif 146 if (_lazyGetterInvoker == null) 147 { 148 if (!CanRead) 149 throw new ArgumentException(); 150 151 _lazyGetterInvoker = Getter.GetUncachedMethodInvoker(Array.Empty<RuntimeTypeInfo>(), this); 152 } 153 if (index == null) 154 index = Array.Empty<Object>(); 155 return _lazyGetterInvoker.Invoke(obj, index, binder, invokeAttr, culture); 156 } 157 HasSameMetadataDefinitionAs(MemberInfo other)158 public abstract override bool HasSameMetadataDefinitionAs(MemberInfo other); 159 160 public sealed override Module Module 161 { 162 get 163 { 164 return DefiningTypeInfo.Module; 165 } 166 } 167 168 public sealed override String Name 169 { 170 get 171 { 172 #if ENABLE_REFLECTION_TRACE 173 if (ReflectionTrace.Enabled) 174 ReflectionTrace.PropertyInfo_Name(this); 175 #endif 176 177 return MetadataName; 178 } 179 } 180 181 public sealed override Type PropertyType 182 { 183 get 184 { 185 #if ENABLE_REFLECTION_TRACE 186 if (ReflectionTrace.Enabled) 187 ReflectionTrace.PropertyInfo_PropertyType(this); 188 #endif 189 190 TypeContext typeContext = ContextTypeInfo.TypeContext; 191 return PropertyTypeHandle.Resolve(typeContext); 192 } 193 } 194 195 public sealed override Type ReflectedType 196 { 197 get 198 { 199 return _reflectedType; 200 } 201 } 202 203 public sealed override MethodInfo SetMethod 204 { 205 get 206 { 207 #if ENABLE_REFLECTION_TRACE 208 if (ReflectionTrace.Enabled) 209 ReflectionTrace.PropertyInfo_SetMethod(this); 210 #endif 211 212 return Setter; 213 } 214 } 215 SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)216 public sealed override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture) 217 { 218 #if ENABLE_REFLECTION_TRACE 219 if (ReflectionTrace.Enabled) 220 ReflectionTrace.PropertyInfo_SetValue(this, obj, value, index); 221 #endif 222 if (_lazySetterInvoker == null) 223 { 224 if (!CanWrite) 225 throw new ArgumentException(); 226 227 _lazySetterInvoker = Setter.GetUncachedMethodInvoker(Array.Empty<RuntimeTypeInfo>(), this); 228 } 229 Object[] arguments; 230 if (index == null) 231 { 232 arguments = new Object[] { value }; 233 } 234 else 235 { 236 arguments = new Object[index.Length + 1]; 237 for (int i = 0; i < index.Length; i++) 238 { 239 arguments[i] = index[i]; 240 } 241 arguments[index.Length] = value; 242 } 243 _lazySetterInvoker.Invoke(obj, arguments, binder, invokeAttr, culture); 244 } 245 ToString()246 public sealed override String ToString() 247 { 248 StringBuilder sb = new StringBuilder(30); 249 250 TypeContext typeContext = ContextTypeInfo.TypeContext; 251 sb.Append(PropertyTypeHandle.FormatTypeName(typeContext)); 252 sb.Append(' '); 253 sb.Append(this.Name); 254 ParameterInfo[] indexParameters = this.GetIndexParameters(); 255 if (indexParameters.Length != 0) 256 { 257 RuntimeParameterInfo[] indexRuntimeParameters = new RuntimeParameterInfo[indexParameters.Length]; 258 for (int i = 0; i < indexParameters.Length; i++) 259 indexRuntimeParameters[i] = (RuntimeParameterInfo)(indexParameters[i]); 260 sb.Append(" ["); 261 sb.Append(RuntimeMethodHelpers.ComputeParametersString(indexRuntimeParameters)); 262 sb.Append(']'); 263 } 264 265 return sb.ToString(); 266 } 267 268 String ITraceableTypeMember.MemberName 269 { 270 get 271 { 272 return MetadataName; 273 } 274 } 275 276 Type ITraceableTypeMember.ContainingType 277 { 278 get 279 { 280 return ContextTypeInfo; 281 } 282 } 283 284 private RuntimeNamedMethodInfo Getter 285 { 286 get 287 { 288 RuntimeNamedMethodInfo getter = _lazyGetter; 289 if (getter == null) 290 { 291 getter = GetPropertyMethod(PropertyMethodSemantics.Getter); 292 293 if (getter == null) 294 getter = RuntimeDummyMethodInfo.Instance; 295 296 _lazyGetter = getter; 297 } 298 299 return object.ReferenceEquals(getter, RuntimeDummyMethodInfo.Instance) ? null : getter; 300 } 301 } 302 303 private RuntimeNamedMethodInfo Setter 304 { 305 get 306 { 307 RuntimeNamedMethodInfo setter = _lazySetter; 308 if (setter == null) 309 { 310 setter = GetPropertyMethod(PropertyMethodSemantics.Setter); 311 312 if (setter == null) 313 setter = RuntimeDummyMethodInfo.Instance; 314 315 _lazySetter = setter; 316 } 317 318 return object.ReferenceEquals(setter, RuntimeDummyMethodInfo.Instance) ? null : setter; 319 } 320 } 321 WithDebugName()322 protected RuntimePropertyInfo WithDebugName() 323 { 324 bool populateDebugNames = DeveloperExperienceState.DeveloperExperienceModeEnabled; 325 #if DEBUG 326 populateDebugNames = true; 327 #endif 328 if (!populateDebugNames) 329 return this; 330 331 if (_debugName == null) 332 { 333 _debugName = "Constructing..."; // Protect against any inadvertent reentrancy. 334 _debugName = MetadataName; 335 } 336 return this; 337 } 338 339 // Types that derive from RuntimePropertyInfo must implement the following public surface area members 340 public abstract override PropertyAttributes Attributes { get; } 341 public abstract override IEnumerable<CustomAttributeData> CustomAttributes { get; } Equals(Object obj)342 public abstract override bool Equals(Object obj); GetHashCode()343 public abstract override int GetHashCode(); 344 public abstract override int MetadataToken { get; } 345 GetConstantValue()346 public sealed override object GetConstantValue() => GetConstantValue(raw: false); GetRawConstantValue()347 public sealed override object GetRawConstantValue() => GetConstantValue(raw: true); 348 GetDefaultValueIfAny(bool raw, out object defaultValue)349 protected abstract bool GetDefaultValueIfAny(bool raw, out object defaultValue); 350 351 /// <summary> 352 /// Return a qualified handle that can be used to get the type of the property. 353 /// </summary> 354 protected abstract QSignatureTypeHandle PropertyTypeHandle { get; } 355 356 protected enum PropertyMethodSemantics 357 { 358 Getter, 359 Setter, 360 } 361 362 /// <summary> 363 /// Override to return the Method that corresponds to the specified semantic. 364 /// Return null if a method of the appropriate semantic does not exist 365 /// </summary> GetPropertyMethod(PropertyMethodSemantics whichMethod)366 protected abstract RuntimeNamedMethodInfo GetPropertyMethod(PropertyMethodSemantics whichMethod); 367 368 /// <summary> 369 /// Override to provide the metadata based name of a property. (Different from the Name 370 /// property in that it does not go into the reflection trace logic.) 371 /// </summary> 372 protected abstract string MetadataName { get; } 373 374 /// <summary> 375 /// Return the DefiningTypeInfo as a RuntimeTypeInfo (instead of as a format specific type info) 376 /// </summary> 377 protected abstract RuntimeTypeInfo DefiningTypeInfo { get; } 378 379 protected readonly RuntimeTypeInfo ContextTypeInfo; 380 protected readonly RuntimeTypeInfo _reflectedType; 381 GetConstantValue(bool raw)382 private object GetConstantValue(bool raw) 383 { 384 #if ENABLE_REFLECTION_TRACE 385 if (ReflectionTrace.Enabled) 386 ReflectionTrace.PropertyInfo_GetConstantValue(this); 387 #endif 388 389 object defaultValue; 390 if (!GetDefaultValueIfAny(raw, out defaultValue)) 391 { 392 throw new InvalidOperationException(SR.Arg_EnumLitValueNotFound); 393 } 394 return defaultValue; 395 } 396 397 private volatile MethodInvoker _lazyGetterInvoker = null; 398 private volatile MethodInvoker _lazySetterInvoker = null; 399 400 private volatile RuntimeNamedMethodInfo _lazyGetter; 401 private volatile RuntimeNamedMethodInfo _lazySetter; 402 403 private volatile ParameterInfo[] _lazyIndexParameters; 404 405 private String _debugName; 406 } 407 } 408 409