File: System\Reflection\Runtime\MethodInfos\CustomMethodMapper.Nullable.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.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reflection.Runtime.General;
using System.Runtime.CompilerServices;

namespace System.Reflection.Runtime.MethodInfos
{
    internal static partial class CustomMethodMapper
    {
        //
        // Nullables are another edge case.
        //
        private static class NullableActions
        {
            public static Dictionary<MethodBase, CustomMethodInvokerAction> Map
            {
                get
                {
                    if (s_lazyMap == null)
                    {
                        Dictionary<MethodBase, CustomMethodInvokerAction> map = new Dictionary<MethodBase, CustomMethodInvokerAction>();

                        Type type = typeof(Nullable<>);
                        Type theT = type.GetGenericTypeParameters()[0];

                        map.AddMethod(type, nameof(Nullable<int>.ToString), Array.Empty<Type>(),
                            (object thisObject, object[] args, Type thisType) =>
                            {
                                return thisObject == null ? string.Empty : thisObject.ToString();
                            }
                        );

                        map.AddMethod(type, nameof(Nullable<int>.Equals), new Type[] { typeof(object) },
                            (object thisObject, object[] args, Type thisType) =>
                            {
                                object other = args[0];
                                if (thisObject == null)
                                    return other == null;
                                if (other == null)
                                    return false;
                                return thisObject.Equals(other);
                            }
                        );

                        map.AddMethod(type, nameof(Nullable<int>.GetHashCode), Array.Empty<Type>(),
                            (object thisObject, object[] args, Type thisType) =>
                            {
                                return thisObject == null ? 0 : thisObject.GetHashCode();
                            }
                        );

                        map.AddConstructor(type, new Type[] { theT },
                            (object thisObject, object[] args, Type thisType) =>
                            {
                                return args[0];
                            }
                         );

                        map.AddMethod(type, "get_" + nameof(Nullable<int>.HasValue), Array.Empty<Type>(),
                            (object thisObject, object[] args, Type thisType) =>
                            {
                                return thisObject != null;
                            }
                        );

                        map.AddMethod(type, "get_" + nameof(Nullable<int>.Value), Array.Empty<Type>(),
                            (object thisObject, object[] args, Type thisType) =>
                            {
                                if (thisObject == null)
                                    throw new InvalidOperationException(SR.InvalidOperation_NoValue);
                                return thisObject;
                            }
                        );

                        map.AddMethod(type, nameof(Nullable<int>.GetValueOrDefault), Array.Empty<Type>(), NullableGetValueOrDefault);

                        [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2067:ParameterDoesntMeetParameterRequirements",
                            Justification = "Constructed MethodTable of a Nullable forces a constructed MethodTable of the element type")]
                        static object NullableGetValueOrDefault(object thisObject, object[] args,
                            Type thisType)
                        {
                            if (thisObject == null)
                                return RuntimeHelpers.GetUninitializedObject(thisType);

                            return thisObject;
                        }

                        map.AddMethod(type, nameof(Nullable<int>.GetValueOrDefault), new Type[] { theT },
                            (object thisObject, object[] args, Type thisType) =>
                            {
                                if (thisObject == null)
                                    return args[0];
                                return thisObject;
                            }
                        );

                        s_lazyMap = map;
                    }

                    return s_lazyMap;
                }
            }

            private static volatile Dictionary<MethodBase, CustomMethodInvokerAction> s_lazyMap;
        }
    }
}