|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Reflection.Runtime.BindingFlagSupport;
using System.Reflection.Runtime.CustomAttributes;
using System.Reflection.Runtime.General;
using System.Reflection.Runtime.TypeInfos;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Internal.Reflection.Core;
using Internal.Reflection.Core.Execution;
namespace System.Reflection.Runtime.FieldInfos
{
//
// The Runtime's implementation of fields.
//
internal abstract partial class RuntimeFieldInfo : FieldInfo
{
//
// contextType - the type that supplies the type context (i.e. substitutions for generic parameters.) Though you
// get your raw information from "definingType", you report "contextType" as your DeclaringType property.
//
// For example:
//
// typeof(Foo<>).GetTypeInfo().DeclaredMembers
//
// The definingType and contextType are both Foo<>
//
// typeof(Foo<int,String>).GetTypeInfo().DeclaredMembers
//
// The definingType is "Foo<,>"
// The contextType is "Foo<int,String>"
//
// We don't report any DeclaredMembers for arrays or generic parameters so those don't apply.
//
protected RuntimeFieldInfo(RuntimeTypeInfo contextTypeInfo, RuntimeTypeInfo reflectedType)
{
_contextTypeInfo = contextTypeInfo;
_reflectedType = reflectedType;
}
public sealed override IEnumerable<CustomAttributeData> CustomAttributes
{
get
{
foreach (CustomAttributeData cad in TrueCustomAttributes)
yield return cad;
if (DeclaringType.IsExplicitLayout)
{
int offset = ExplicitLayoutFieldOffsetData;
CustomAttributeTypedArgument offsetArgument = new CustomAttributeTypedArgument(typeof(int), offset);
yield return new RuntimePseudoCustomAttributeData(typeof(FieldOffsetAttribute), new CustomAttributeTypedArgument[] { offsetArgument });
}
FieldAttributes attributes = Attributes;
#pragma warning disable SYSLIB0050 // Legacy serialization infrastructure is obsolete
if (0 != (attributes & FieldAttributes.NotSerialized))
{
yield return new RuntimePseudoCustomAttributeData(typeof(NonSerializedAttribute), null);
}
#pragma warning restore SYSLIB0050
}
}
public sealed override Type DeclaringType
{
get
{
return _contextTypeInfo.ToType();
}
}
public sealed override Type FieldType
{
get
{
Type fieldType = _lazyFieldType;
if (fieldType == null)
{
_lazyFieldType = fieldType = this.FieldRuntimeType.ToType();
}
return fieldType;
}
}
public abstract override Type[] GetOptionalCustomModifiers();
public abstract override Type[] GetRequiredCustomModifiers();
public sealed override object GetValue(object obj)
{
FieldAccessor fieldAccessor = this.FieldAccessor;
return fieldAccessor.GetField(obj);
}
public sealed override object GetValueDirect(TypedReference obj)
{
if (obj.IsNull)
throw new ArgumentException(SR.Arg_TypedReference_Null);
FieldAccessor fieldAccessor = this.FieldAccessor;
return fieldAccessor.GetFieldDirect(obj);
}
public abstract override bool HasSameMetadataDefinitionAs(MemberInfo other);
public sealed override Module Module
{
get
{
return DefiningType.Module;
}
}
public sealed override Type ReflectedType
{
get
{
return _reflectedType.ToType();
}
}
public sealed override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, CultureInfo culture)
{
FieldAccessor fieldAccessor = this.FieldAccessor;
BinderBundle binderBundle = binder.ToBinderBundle(invokeAttr, culture);
fieldAccessor.SetField(obj, value, binderBundle);
}
public sealed override void SetValueDirect(TypedReference obj, object value)
{
if (obj.IsNull)
throw new ArgumentException(SR.Arg_TypedReference_Null);
FieldAccessor fieldAccessor = this.FieldAccessor;
fieldAccessor.SetFieldDirect(obj, value);
}
/// <summary>
/// Override to provide the metadata based name of a field. (Different from the Name
/// property in that it does not go into the reflection trace logic.)
/// </summary>
protected abstract string MetadataName { get; }
public sealed override string Name
{
get
{
return MetadataName;
}
}
public sealed override object GetRawConstantValue()
{
if (!IsLiteral)
throw new InvalidOperationException();
object defaultValue;
if (!GetDefaultValueIfAvailable(raw: true, defaultValue: out defaultValue))
throw new BadImageFormatException(); // Field marked literal but has no default value.
return defaultValue;
}
// Types that derive from RuntimeFieldInfo must implement the following public surface area members
public abstract override FieldAttributes Attributes { get; }
public abstract override int MetadataToken { get; }
public abstract override string ToString();
public abstract override bool Equals(object obj);
public abstract override int GetHashCode();
public abstract override RuntimeFieldHandle FieldHandle { get; }
/// <summary>
/// Get the default value if exists for a field by parsing metadata. Return false if there is no default value.
/// </summary>
protected abstract bool GetDefaultValueIfAvailable(bool raw, out object defaultValue);
/// <summary>
/// Return a FieldAccessor object for accessing the value of a non-literal field. May rely on metadata to create correct accessor.
/// </summary>
protected abstract FieldAccessor TryGetFieldAccessor();
private FieldAccessor FieldAccessor
{
get
{
FieldAccessor fieldAccessor = _lazyFieldAccessor;
if (fieldAccessor == null)
{
if (this.IsLiteral)
{
// Legacy: ECMA335 does not require that the metadata literal match the type of the field that declares it.
// For desktop compat, we return the metadata literal as is and do not attempt to convert or validate against the Field type.
object defaultValue;
if (!GetDefaultValueIfAvailable(raw: false, defaultValue: out defaultValue))
{
throw new BadImageFormatException(); // Field marked literal but has no default value.
}
_lazyFieldAccessor = fieldAccessor = ReflectionCoreExecution.ExecutionEnvironment.CreateLiteralFieldAccessor(defaultValue, FieldType.TypeHandle);
}
else
{
_lazyFieldAccessor = fieldAccessor = TryGetFieldAccessor();
if (fieldAccessor == null)
throw ReflectionCoreExecution.ExecutionEnvironment.CreateNonInvokabilityException(this);
}
}
return fieldAccessor;
}
}
/// <summary>
/// Return the type of the field by parsing metadata.
/// </summary>
protected abstract RuntimeTypeInfo FieldRuntimeType { get; }
protected RuntimeFieldInfo WithDebugName()
{
#if DEBUG
if (_debugName == null)
{
_debugName = "Constructing..."; // Protect against any inadvertent reentrancy.
_debugName = MetadataName;
}
#endif
return this;
}
/// <summary>
/// Return the DefiningTypeInfo as a RuntimeTypeInfo (instead of as a format specific type info)
/// </summary>
protected abstract RuntimeTypeInfo DefiningType { get; }
protected abstract IEnumerable<CustomAttributeData> TrueCustomAttributes { get; }
protected abstract int ExplicitLayoutFieldOffsetData { get; }
/// <summary>
/// Returns the field offset (asserts and throws if not an instance field). Does not include the size of the object header.
/// </summary>
internal int Offset => FieldAccessor.Offset;
protected readonly RuntimeTypeInfo _contextTypeInfo;
protected readonly RuntimeTypeInfo _reflectedType;
private volatile FieldAccessor _lazyFieldAccessor;
private volatile Type _lazyFieldType;
#if DEBUG
private string _debugName;
#endif
}
}
|