File: System\Runtime\Serialization\Formatters\Binary\Converter.cs
Web Access
Project: src\src\libraries\System.Runtime.Serialization.Formatters\src\System.Runtime.Serialization.Formatters.csproj (System.Runtime.Serialization.Formatters)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection;
 
namespace System.Runtime.Serialization.Formatters.Binary
{
    internal static class Converter
    {
        internal static readonly Type s_typeofISerializable = typeof(ISerializable);
        internal static readonly Type s_typeofString = typeof(string);
        internal static readonly Type s_typeofConverter = typeof(Converter);
        internal static readonly Type s_typeofBoolean = typeof(bool);
        internal static readonly Type s_typeofByte = typeof(byte);
        internal static readonly Type s_typeofChar = typeof(char);
        internal static readonly Type s_typeofDecimal = typeof(decimal);
        internal static readonly Type s_typeofDouble = typeof(double);
        internal static readonly Type s_typeofInt16 = typeof(short);
        internal static readonly Type s_typeofInt32 = typeof(int);
        internal static readonly Type s_typeofInt64 = typeof(long);
        internal static readonly Type s_typeofSByte = typeof(sbyte);
        internal static readonly Type s_typeofSingle = typeof(float);
        internal static readonly Type s_typeofTimeSpan = typeof(TimeSpan);
        internal static readonly Type s_typeofDateTime = typeof(DateTime);
        internal static readonly Type s_typeofUInt16 = typeof(ushort);
        internal static readonly Type s_typeofUInt32 = typeof(uint);
        internal static readonly Type s_typeofUInt64 = typeof(ulong);
        internal static readonly Type s_typeofObject = typeof(object);
        internal static readonly Type s_typeofSystemVoid = typeof(void);
 
        // In .NET Framework the default assembly is mscorlib.dll --> typeof(string).Assembly.
        // In Core type string lives in System.Private.Corelib.dll which doesn't
        // contain all the types which are living in mscorlib in .NET Framework. Therefore we
        // use our mscorlib facade which also contains manual type forwards for deserialization.
        internal static readonly Assembly s_urtAssembly = Assembly.Load("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
        internal static readonly string s_urtAssemblyString = s_urtAssembly.FullName!;
 
        internal static readonly Assembly s_urtAlternativeAssembly = s_typeofString.Assembly;
        internal static readonly string s_urtAlternativeAssemblyString = s_urtAlternativeAssembly.FullName!;
 
        // Arrays
        internal static readonly Type s_typeofTypeArray = typeof(Type[]);
        internal static readonly Type s_typeofObjectArray = typeof(object[]);
        internal static readonly Type s_typeofStringArray = typeof(string[]);
        internal static readonly Type s_typeofBooleanArray = typeof(bool[]);
        internal static readonly Type s_typeofByteArray = typeof(byte[]);
        internal static readonly Type s_typeofCharArray = typeof(char[]);
        internal static readonly Type s_typeofDecimalArray = typeof(decimal[]);
        internal static readonly Type s_typeofDoubleArray = typeof(double[]);
        internal static readonly Type s_typeofInt16Array = typeof(short[]);
        internal static readonly Type s_typeofInt32Array = typeof(int[]);
        internal static readonly Type s_typeofInt64Array = typeof(long[]);
        internal static readonly Type s_typeofSByteArray = typeof(sbyte[]);
        internal static readonly Type s_typeofSingleArray = typeof(float[]);
        internal static readonly Type s_typeofTimeSpanArray = typeof(TimeSpan[]);
        internal static readonly Type s_typeofDateTimeArray = typeof(DateTime[]);
        internal static readonly Type s_typeofUInt16Array = typeof(ushort[]);
        internal static readonly Type s_typeofUInt32Array = typeof(uint[]);
        internal static readonly Type s_typeofUInt64Array = typeof(ulong[]);
        internal static readonly Type s_typeofMarshalByRefObject = typeof(MarshalByRefObject);
 
        private const int PrimitiveTypeEnumLength = 17; //Number of PrimitiveTypeEnums
 
        private static volatile Type?[]? s_typeA;
        private static volatile Type?[]? s_arrayTypeA;
        private static volatile string?[]? s_valueA;
        private static volatile TypeCode[]? s_typeCodeA;
        private static volatile InternalPrimitiveTypeE[]? s_codeA;
 
        internal static InternalPrimitiveTypeE ToCode(Type? type) =>
                type == null ? ToPrimitiveTypeEnum(TypeCode.Empty) :
                type.IsPrimitive ? ToPrimitiveTypeEnum(Type.GetTypeCode(type)) :
                ReferenceEquals(type, s_typeofDateTime) ? InternalPrimitiveTypeE.DateTime :
                ReferenceEquals(type, s_typeofTimeSpan) ? InternalPrimitiveTypeE.TimeSpan :
                ReferenceEquals(type, s_typeofDecimal) ? InternalPrimitiveTypeE.Decimal :
                InternalPrimitiveTypeE.Invalid;
 
        internal static bool IsWriteAsByteArray(InternalPrimitiveTypeE code)
        {
            switch (code)
            {
                case InternalPrimitiveTypeE.Boolean:
                case InternalPrimitiveTypeE.Char:
                case InternalPrimitiveTypeE.Byte:
                case InternalPrimitiveTypeE.Double:
                case InternalPrimitiveTypeE.Int16:
                case InternalPrimitiveTypeE.Int32:
                case InternalPrimitiveTypeE.Int64:
                case InternalPrimitiveTypeE.SByte:
                case InternalPrimitiveTypeE.Single:
                case InternalPrimitiveTypeE.UInt16:
                case InternalPrimitiveTypeE.UInt32:
                case InternalPrimitiveTypeE.UInt64:
                    return true;
                default:
                    return false;
            }
        }
 
        internal static int TypeLength(InternalPrimitiveTypeE code) =>
            code switch
            {
                InternalPrimitiveTypeE.Boolean => 1,
                InternalPrimitiveTypeE.Char => 2,
                InternalPrimitiveTypeE.Byte => 1,
                InternalPrimitiveTypeE.Double => 8,
                InternalPrimitiveTypeE.Int16 => 2,
                InternalPrimitiveTypeE.Int32 => 4,
                InternalPrimitiveTypeE.Int64 => 8,
                InternalPrimitiveTypeE.SByte => 1,
                InternalPrimitiveTypeE.Single => 4,
                InternalPrimitiveTypeE.UInt16 => 2,
                InternalPrimitiveTypeE.UInt32 => 4,
                InternalPrimitiveTypeE.UInt64 => 8,
                _ => 0,
            };
 
        internal static Type? ToArrayType(InternalPrimitiveTypeE code)
        {
            if (s_arrayTypeA == null)
            {
                InitArrayTypeA();
            }
            return s_arrayTypeA![(int)code];
        }
 
        private static void InitTypeA()
        {
            var typeATemp = new Type?[PrimitiveTypeEnumLength];
            typeATemp[(int)InternalPrimitiveTypeE.Invalid] = null;
            typeATemp[(int)InternalPrimitiveTypeE.Boolean] = s_typeofBoolean;
            typeATemp[(int)InternalPrimitiveTypeE.Byte] = s_typeofByte;
            typeATemp[(int)InternalPrimitiveTypeE.Char] = s_typeofChar;
            typeATemp[(int)InternalPrimitiveTypeE.Decimal] = s_typeofDecimal;
            typeATemp[(int)InternalPrimitiveTypeE.Double] = s_typeofDouble;
            typeATemp[(int)InternalPrimitiveTypeE.Int16] = s_typeofInt16;
            typeATemp[(int)InternalPrimitiveTypeE.Int32] = s_typeofInt32;
            typeATemp[(int)InternalPrimitiveTypeE.Int64] = s_typeofInt64;
            typeATemp[(int)InternalPrimitiveTypeE.SByte] = s_typeofSByte;
            typeATemp[(int)InternalPrimitiveTypeE.Single] = s_typeofSingle;
            typeATemp[(int)InternalPrimitiveTypeE.TimeSpan] = s_typeofTimeSpan;
            typeATemp[(int)InternalPrimitiveTypeE.DateTime] = s_typeofDateTime;
            typeATemp[(int)InternalPrimitiveTypeE.UInt16] = s_typeofUInt16;
            typeATemp[(int)InternalPrimitiveTypeE.UInt32] = s_typeofUInt32;
            typeATemp[(int)InternalPrimitiveTypeE.UInt64] = s_typeofUInt64;
            s_typeA = typeATemp;
        }
 
        private static void InitArrayTypeA()
        {
            var arrayTypeATemp = new Type?[PrimitiveTypeEnumLength];
            arrayTypeATemp[(int)InternalPrimitiveTypeE.Invalid] = null;
            arrayTypeATemp[(int)InternalPrimitiveTypeE.Boolean] = s_typeofBooleanArray;
            arrayTypeATemp[(int)InternalPrimitiveTypeE.Byte] = s_typeofByteArray;
            arrayTypeATemp[(int)InternalPrimitiveTypeE.Char] = s_typeofCharArray;
            arrayTypeATemp[(int)InternalPrimitiveTypeE.Decimal] = s_typeofDecimalArray;
            arrayTypeATemp[(int)InternalPrimitiveTypeE.Double] = s_typeofDoubleArray;
            arrayTypeATemp[(int)InternalPrimitiveTypeE.Int16] = s_typeofInt16Array;
            arrayTypeATemp[(int)InternalPrimitiveTypeE.Int32] = s_typeofInt32Array;
            arrayTypeATemp[(int)InternalPrimitiveTypeE.Int64] = s_typeofInt64Array;
            arrayTypeATemp[(int)InternalPrimitiveTypeE.SByte] = s_typeofSByteArray;
            arrayTypeATemp[(int)InternalPrimitiveTypeE.Single] = s_typeofSingleArray;
            arrayTypeATemp[(int)InternalPrimitiveTypeE.TimeSpan] = s_typeofTimeSpanArray;
            arrayTypeATemp[(int)InternalPrimitiveTypeE.DateTime] = s_typeofDateTimeArray;
            arrayTypeATemp[(int)InternalPrimitiveTypeE.UInt16] = s_typeofUInt16Array;
            arrayTypeATemp[(int)InternalPrimitiveTypeE.UInt32] = s_typeofUInt32Array;
            arrayTypeATemp[(int)InternalPrimitiveTypeE.UInt64] = s_typeofUInt64Array;
            s_arrayTypeA = arrayTypeATemp;
        }
 
        internal static Type? ToType(InternalPrimitiveTypeE code)
        {
            if (s_typeA == null)
            {
                InitTypeA();
            }
            return s_typeA![(int)code];
        }
 
        internal static Array? CreatePrimitiveArray(InternalPrimitiveTypeE code, int length) =>
            code switch
            {
                InternalPrimitiveTypeE.Boolean => new bool[length],
                InternalPrimitiveTypeE.Byte => new byte[length],
                InternalPrimitiveTypeE.Char => new char[length],
                InternalPrimitiveTypeE.Decimal => new decimal[length],
                InternalPrimitiveTypeE.Double => new double[length],
                InternalPrimitiveTypeE.Int16 => new short[length],
                InternalPrimitiveTypeE.Int32 => new int[length],
                InternalPrimitiveTypeE.Int64 => new long[length],
                InternalPrimitiveTypeE.SByte => new sbyte[length],
                InternalPrimitiveTypeE.Single => new float[length],
                InternalPrimitiveTypeE.TimeSpan => new TimeSpan[length],
                InternalPrimitiveTypeE.DateTime => new DateTime[length],
                InternalPrimitiveTypeE.UInt16 => new ushort[length],
                InternalPrimitiveTypeE.UInt32 => new uint[length],
                InternalPrimitiveTypeE.UInt64 => new ulong[length],
                _ => null,
            };
 
        internal static bool IsPrimitiveArray(Type? type, [NotNullWhen(true)] out object? typeInformation)
        {
            if (ReferenceEquals(type, s_typeofBooleanArray)) typeInformation = InternalPrimitiveTypeE.Boolean;
            else if (ReferenceEquals(type, s_typeofByteArray)) typeInformation = InternalPrimitiveTypeE.Byte;
            else if (ReferenceEquals(type, s_typeofCharArray)) typeInformation = InternalPrimitiveTypeE.Char;
            else if (ReferenceEquals(type, s_typeofDoubleArray)) typeInformation = InternalPrimitiveTypeE.Double;
            else if (ReferenceEquals(type, s_typeofInt16Array)) typeInformation = InternalPrimitiveTypeE.Int16;
            else if (ReferenceEquals(type, s_typeofInt32Array)) typeInformation = InternalPrimitiveTypeE.Int32;
            else if (ReferenceEquals(type, s_typeofInt64Array)) typeInformation = InternalPrimitiveTypeE.Int64;
            else if (ReferenceEquals(type, s_typeofSByteArray)) typeInformation = InternalPrimitiveTypeE.SByte;
            else if (ReferenceEquals(type, s_typeofSingleArray)) typeInformation = InternalPrimitiveTypeE.Single;
            else if (ReferenceEquals(type, s_typeofUInt16Array)) typeInformation = InternalPrimitiveTypeE.UInt16;
            else if (ReferenceEquals(type, s_typeofUInt32Array)) typeInformation = InternalPrimitiveTypeE.UInt32;
            else if (ReferenceEquals(type, s_typeofUInt64Array)) typeInformation = InternalPrimitiveTypeE.UInt64;
            else
            {
                typeInformation = null;
                return false;
            }
 
            return true;
        }
 
        private static void InitValueA()
        {
            var valueATemp = new string?[PrimitiveTypeEnumLength];
            valueATemp[(int)InternalPrimitiveTypeE.Invalid] = null;
            valueATemp[(int)InternalPrimitiveTypeE.Boolean] = "Boolean";
            valueATemp[(int)InternalPrimitiveTypeE.Byte] = "Byte";
            valueATemp[(int)InternalPrimitiveTypeE.Char] = "Char";
            valueATemp[(int)InternalPrimitiveTypeE.Decimal] = "Decimal";
            valueATemp[(int)InternalPrimitiveTypeE.Double] = "Double";
            valueATemp[(int)InternalPrimitiveTypeE.Int16] = "Int16";
            valueATemp[(int)InternalPrimitiveTypeE.Int32] = "Int32";
            valueATemp[(int)InternalPrimitiveTypeE.Int64] = "Int64";
            valueATemp[(int)InternalPrimitiveTypeE.SByte] = "SByte";
            valueATemp[(int)InternalPrimitiveTypeE.Single] = "Single";
            valueATemp[(int)InternalPrimitiveTypeE.TimeSpan] = "TimeSpan";
            valueATemp[(int)InternalPrimitiveTypeE.DateTime] = "DateTime";
            valueATemp[(int)InternalPrimitiveTypeE.UInt16] = "UInt16";
            valueATemp[(int)InternalPrimitiveTypeE.UInt32] = "UInt32";
            valueATemp[(int)InternalPrimitiveTypeE.UInt64] = "UInt64";
            s_valueA = valueATemp;
        }
 
        internal static string? ToComType(InternalPrimitiveTypeE code)
        {
            if (s_valueA == null)
            {
                InitValueA();
            }
            return s_valueA![(int)code];
        }
 
        private static void InitTypeCodeA()
        {
            var typeCodeATemp = new TypeCode[PrimitiveTypeEnumLength];
            typeCodeATemp[(int)InternalPrimitiveTypeE.Invalid] = TypeCode.Object;
            typeCodeATemp[(int)InternalPrimitiveTypeE.Boolean] = TypeCode.Boolean;
            typeCodeATemp[(int)InternalPrimitiveTypeE.Byte] = TypeCode.Byte;
            typeCodeATemp[(int)InternalPrimitiveTypeE.Char] = TypeCode.Char;
            typeCodeATemp[(int)InternalPrimitiveTypeE.Decimal] = TypeCode.Decimal;
            typeCodeATemp[(int)InternalPrimitiveTypeE.Double] = TypeCode.Double;
            typeCodeATemp[(int)InternalPrimitiveTypeE.Int16] = TypeCode.Int16;
            typeCodeATemp[(int)InternalPrimitiveTypeE.Int32] = TypeCode.Int32;
            typeCodeATemp[(int)InternalPrimitiveTypeE.Int64] = TypeCode.Int64;
            typeCodeATemp[(int)InternalPrimitiveTypeE.SByte] = TypeCode.SByte;
            typeCodeATemp[(int)InternalPrimitiveTypeE.Single] = TypeCode.Single;
            typeCodeATemp[(int)InternalPrimitiveTypeE.TimeSpan] = TypeCode.Object;
            typeCodeATemp[(int)InternalPrimitiveTypeE.DateTime] = TypeCode.DateTime;
            typeCodeATemp[(int)InternalPrimitiveTypeE.UInt16] = TypeCode.UInt16;
            typeCodeATemp[(int)InternalPrimitiveTypeE.UInt32] = TypeCode.UInt32;
            typeCodeATemp[(int)InternalPrimitiveTypeE.UInt64] = TypeCode.UInt64;
            s_typeCodeA = typeCodeATemp;
        }
 
        // Returns a System.TypeCode from a InternalPrimitiveTypeE
        internal static TypeCode ToTypeCode(InternalPrimitiveTypeE code)
        {
            if (s_typeCodeA == null)
            {
                InitTypeCodeA();
            }
            return s_typeCodeA![(int)code];
        }
 
        private static void InitCodeA()
        {
            var codeATemp = new InternalPrimitiveTypeE[19];
            codeATemp[(int)TypeCode.Empty] = InternalPrimitiveTypeE.Invalid;
            codeATemp[(int)TypeCode.Object] = InternalPrimitiveTypeE.Invalid;
            codeATemp[(int)TypeCode.DBNull] = InternalPrimitiveTypeE.Invalid;
            codeATemp[(int)TypeCode.Boolean] = InternalPrimitiveTypeE.Boolean;
            codeATemp[(int)TypeCode.Char] = InternalPrimitiveTypeE.Char;
            codeATemp[(int)TypeCode.SByte] = InternalPrimitiveTypeE.SByte;
            codeATemp[(int)TypeCode.Byte] = InternalPrimitiveTypeE.Byte;
            codeATemp[(int)TypeCode.Int16] = InternalPrimitiveTypeE.Int16;
            codeATemp[(int)TypeCode.UInt16] = InternalPrimitiveTypeE.UInt16;
            codeATemp[(int)TypeCode.Int32] = InternalPrimitiveTypeE.Int32;
            codeATemp[(int)TypeCode.UInt32] = InternalPrimitiveTypeE.UInt32;
            codeATemp[(int)TypeCode.Int64] = InternalPrimitiveTypeE.Int64;
            codeATemp[(int)TypeCode.UInt64] = InternalPrimitiveTypeE.UInt64;
            codeATemp[(int)TypeCode.Single] = InternalPrimitiveTypeE.Single;
            codeATemp[(int)TypeCode.Double] = InternalPrimitiveTypeE.Double;
            codeATemp[(int)TypeCode.Decimal] = InternalPrimitiveTypeE.Decimal;
            codeATemp[(int)TypeCode.DateTime] = InternalPrimitiveTypeE.DateTime;
            codeATemp[17] = InternalPrimitiveTypeE.Invalid;
            codeATemp[(int)TypeCode.String] = InternalPrimitiveTypeE.Invalid;
            s_codeA = codeATemp;
        }
 
        // Returns a InternalPrimitiveTypeE from a System.TypeCode
        internal static InternalPrimitiveTypeE ToPrimitiveTypeEnum(TypeCode typeCode)
        {
            if (s_codeA == null)
            {
                InitCodeA();
            }
            return s_codeA![(int)typeCode];
        }
 
        // Translates a string into an Object
        internal static object? FromString(string? value, InternalPrimitiveTypeE code)
        {
            // InternalPrimitiveTypeE needs to be a primitive type
            Debug.Assert((code != InternalPrimitiveTypeE.Invalid), "[Converter.FromString]!InternalPrimitiveTypeE.Invalid ");
            return code != InternalPrimitiveTypeE.Invalid ?
                Convert.ChangeType(value, ToTypeCode(code), CultureInfo.InvariantCulture) :
                value;
        }
    }
}