File: System\TypedReference.cs
Web Access
Project: src\src\runtime\src\coreclr\nativeaot\System.Private.CoreLib\src\System.Private.CoreLib.csproj (System.Private.CoreLib)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Reflection;
using System.Runtime;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

using Internal.Reflection.Augments;
using Internal.Runtime;
using Internal.Runtime.CompilerServices;

namespace System
{
    [CLSCompliant(false)]
    [StructLayout(LayoutKind.Sequential)]
    public ref struct TypedReference
    {
        // Do not change the ordering of these fields. The JIT has a dependency on this layout.
        private readonly ref byte _value;
        private readonly RuntimeTypeHandle _typeHandle;

        private TypedReference(object target, int offset, RuntimeTypeHandle typeHandle)
        {
            _value = ref Unsafe.Add<byte>(ref target.GetRawData(), offset);
            _typeHandle = typeHandle;
        }

        public static TypedReference MakeTypedReference(object target, FieldInfo[] flds)
        {
            Type type;
            int offset;
            ReflectionAugments.MakeTypedReference(target, flds, out type, out offset);
            return new TypedReference(target, offset, type.TypeHandle);
        }

        public static Type? GetTargetType(TypedReference value) => Type.GetTypeFromHandle(value._typeHandle);

        public static RuntimeTypeHandle TargetTypeToken(TypedReference value)
        {
            if (value._typeHandle.IsNull)
                throw new NullReferenceException(); // For compatibility;
            return value._typeHandle;
        }

        public static unsafe object ToObject(TypedReference value)
        {
            RuntimeTypeHandle handle = value._typeHandle;

            if (handle.IsNull)
                ThrowHelper.ThrowArgumentException_ArgumentNull_TypedRefType();

            MethodTable* mt = handle.ToMethodTable();
            if (mt->IsPointer || mt->IsFunctionPointer)
            {
                handle = typeof(UIntPtr).TypeHandle;
            }

            return RuntimeHelpers.Box(ref value.Value, handle);
        }

        public static void SetTypedReference(TypedReference target, object? value) { throw new NotSupportedException(); }

        public override bool Equals(object? o) { throw new NotSupportedException(SR.NotSupported_NYI); }
        public override int GetHashCode() => _typeHandle.IsNull ? 0 : _typeHandle.GetHashCode();

        internal bool IsNull => _typeHandle.IsNull;

        internal ref byte Value
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get
            {
                return ref _value;
            }
        }

        // Implementation of CORINFO_HELP_GETREFANY
        internal static ref byte GetRefAny(RuntimeTypeHandle type, TypedReference value)
        {
            if (!value._typeHandle.Equals(type))
            {
                ThrowInvalidCastException();
            }

            return ref value.Value;

            static void ThrowInvalidCastException() => throw new InvalidCastException();
        }
    }
}