Explicit conversion in C #

Most programming languages support display conversion, also known as coercion, which corresponds to implicit conversion. For example, in general, integer can be implicitly converted to floating-point type, while floating-point type needs to be converted to integer through coercion:

    int i = 32;
    double d = i;//Implicit conversion of integer to floating point
    int j = (int)d;//Convert floating point display to integer

Currently, the following implicit transformations are available in C #:

1. All implicit conversions

Implicit conversion is automatically completed, and implicit conversion also supports forced conversion, which is understandable.

2. Explicit numeric type conversion

Explicit numeric conversion includes:

    1,sbyte Types can be explicitly converted to byte, ushort, uint, ulong, char.
    2,byte Types can be explicitly converted to sbyte, char.
    3,short Types can be explicitly converted to sbyte, byte, ushort, uint, ulong, char.
    4,ushort Types can be explicitly converted to sbyte, byte, short, or char.
    5,int Types can be explicitly converted to sbyte, byte, short, ushort, uint, ulong, char.
    6,uint Types can be explicitly converted to sbyte, byte, short, ushort, int, char.
    7,long Types can be explicitly converted to sbyte, byte, short, ushort, int, uint, ulong, char.
    8,ulong Types can be explicitly converted to sbyte, byte, short, ushort, int, uint, long, char.
    9,char Types can be explicitly converted to sbyte, byte, or short.
    10,float Types can be explicitly converted to sbyte, byte, short, ushort, int, uint, long, ulong, char, decimal.
    11,double Types can be explicitly converted to sbyte, byte, short, ushort, int, uint, long, ulong, char, float, decimal.
    12,decimal Types can be explicitly converted to sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double.

It should be noted that when converting numeric types, precision may be lost or exceptions may be thrown. The conversion rules are as follows:

  • The conversion of integer data to another integer data depends on whether checked and unchecked context detection is used:
        For example: integer( S)Explicitly convert to integer( T)
        
        1,use checked When context detection, when S Data in T Within the allowable range, the conversion can be carried out successfully, otherwise thrown System.OverflowException
        2,use unchecked During context detection:
            When S The number of digits is greater than T The extra high bits (binary) will be intercepted during conversion, and the remaining bits will be used as T data output
            When S The number of digits is less than T When the number of bits is, the S Expand the data (binary) (unsigned integers use 0 to expand, signed integers use 1 to expand if less than 0, otherwise use 0 to expand), and take the expanded value as T data output
            When S Number of digits and T When the number of bits is equal, there is no need to intercept or expand, S Direct conversion of data to T data
        3,not used checked and unchecked During context detection, the default context detection method (generally unchecked)

    For example:

        //--------------------------------------checked Context detection--------------------------------------------------
        
        long l1 = 100000L;
        int value1 = checked((int)l1);      //Normal conversion
        int value2 = checked((int)(l1 * l1));//report errors OverflowException
        
        //--------------------------------------unchecked Context detection--------------------------------------------------
        
        long l2 = 100000L * 100000L;//10000000000
        int value3 = unchecked((int)l2);//1410065408
        //long It's 64 bit>int 32 bits, l2 Binary: 0100101010000001011111001000000000
        //Intercept the extra three high bits to obtain the remaining 32-bit binary: 010101000000101111100100000000, i.e. 1410065408
        
        sbyte b = -1;//Signed 8-bit
        uint value4 = unchecked((uint)b);//4294967295
        //sbyte It's eight<uint 32 bits, b Binary: 1111111111111111111
        //because sbyte Is a signed integer and b<0,Therefore, use 1 to expand the high bit to get 32-bit binary: 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111    
        
        uint ui = 3147483647;
        int value5 = unchecked((int)ui);//-1147483649
        //uint It's 32 bits=int 32 bits, ui Binary: 10111011100110101100100111111111
        //So directly int Binary: 10111011100110101100100111111111, i.e-1147483649
  • When a decimal floating-point number is forcibly converted to integer data, it will round to zero and discard the decimal part. If the rounded value is not within the range allowed by the conversion type, it will throw system Overflow exception, for example:
        decimal d1 = 1.6m;
        decimal d2 = -1.6m;
        decimal d3 = 314m;
        sbyte b1 = (sbyte)d1;//1
        sbyte b2 = (sbyte)d2;//-1
        sbyte b3 = (sbyte)d3;//report errors System.OverflowException
  • When converting float and double to integer data, it depends on whether checked and unchecked context detection is used:
        1,use checked Context detection:
            If float perhaps double Value is NaN Or infinity( NegativeInfinity and PositiveInfinity),Will be thrown System.OverflowException
            Otherwise it will float perhaps double The value is rounded to zero and the decimal part is discarded. If the rounded value is not within the allowable range of integer type, it will be thrown System.OverflowException
        2,use unchecked During context detection:
            If float perhaps double Value is NaN Or infinity( NegativeInfinity and PositiveInfinity),The conversion is cancelled and the default value of the integer is returned
            Otherwise it will float perhaps double The value is rounded to zero and the decimal part is discarded. If the rounded value is not within the allowable range of integer type, the conversion will be cancelled and the default value of integer type will be returned(The official documents are inaccurate. See the following example)
        3,not used checked and unchecked During context detection, the default context detection method (generally unchecked)

    For example:

        double d1 = double.NaN;
        double d2 = 1.6d;
        double d3 = -1.6d;
        double d4 = 3147483647.25d;
        double d5 = 314.25d;
        
        //--------------------------checked Context detection----------------------------------
        
        sbyte b1 = checked((sbyte)d1);//report errors System.OverflowException
        sbyte b2 = checked((sbyte)d2);//1
        sbyte b3 = checked((sbyte)d3);//-1
        sbyte b4 = checked((sbyte)d4);//report errors System.OverflowException
        
        //--------------------------unchecked Context detection--------------------------------
        
        sbyte b5 = unchecked((sbyte)double.PositiveInfinity);   //0
        sbyte b6 = unchecked((sbyte)2.5d);                      //2
        sbyte b7 = unchecked((sbyte)-3.5d);                     //-3
        sbyte b8 = unchecked((sbyte)314.25d);                   //0
        byte b9 = unchecked((byte)257.25d);                     //0
        short b10 = unchecked((short)3147483647.25d);           //0
        int b11 = unchecked((int)3147483647.25d);               //0
        
        //The following is different from the official document (find out the reason when you have time. It may be a problem with the settings at compile time and runtime)
        int b12 = unchecked((int)d4);                           //-2147483648
        sbyte b13 = unchecked((sbyte)d5);                       //58
  • When double is cast to float, follow the rules:
        1,Normally, double The value is passed to the nearest float Values are rounded (not rounded) to ensure that the loss of accuracy is relatively small
        2,If one double The value of infinity tends to 0 when the precision exceeds float Allowable accuracy( float.Epsilon),Will+0 perhaps-0 Returned as a result, depending on double Is it positive or negative
        3,If one double The value is very large, greater than float Returns infinity to the allowed range( float.NegativeInfinity perhaps float.PositiveInfinity,It depends on double (positive or negative)

    For example:

        double d0 = 3.1415d;
        double d1 = 3.141592653589793d;
        double d2 = double.NaN;
        double d3 = 3.14E-100d;
        double d4 = -3.14E-100d;
        double d5 = double.MaxValue;
        double d6 = double.MinValue;
        
        float f0 = (float)d0;//3.1415
        float f1 = (float)d1;//3.1415927
        float f2 = (float)d2;//NaN
        float f3 = (float)d3;//+0
        float f4 = (float)d4;//-0
        float f5 = (float)d5;//float.PositiveInfinity
        float f6 = (float)d6;//float.NegativeInfinity
  • When double and float are forcibly converted to decimal, follow the rules:

        1,In general, double and float Values are converted directly to decimal,When the small data exceeds 28 bits, it will be automatically selected if necessary
        2,If double and float If the value is too small and tends to 0, 0 will be returned directly
        3,If double and float Value is NaN,Infinity, or more than decimal Run range, then it will be thrown System.OverflowException

    For example:

        double d0 = 3.1415d;
        double d1 = 3.14159265358979323d;
        double d2 = double.NaN;
        double d3 = 3.14E-200d;
        double d4 = -3.14E-200d;
        double d5 = double.MaxValue;
        double d6 = double.MinValue;
        
        decimal value0 = (decimal)d0;//3.1415
        decimal value1 = (decimal)d1;//3.14159265358979
        decimal value2 = (decimal)d2;//Throw System.OverflowException
        decimal value3 = (decimal)d3;//0
        decimal value4 = (decimal)d4;//0
        decimal value5 = (decimal)d5;//Throw System.OverflowException
        decimal value6 = (decimal)d6;//Throw System.OverflowException
  • When a decimal is forcibly converted to double or float, it can be converted successfully without throwing any exceptions, but it may cause the loss of precision, for example:

        decimal d0 = 3.1415m;
        decimal d1 = 3.14159265358979323m;
        
        float value0 = (float)d0;//3.1415
        float value1 = (float)d1;//3.1415927

3. Explicit enumeration type conversion

Explicit enumeration type conversions include:

    1,sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal Can be explicitly converted to any enumeration type.
    2,Any enumeration type can be explicitly converted to sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal.
    3,Explicit conversions can be made between any two enumeration types.

In fact, the bottom layer of enumeration type is still integer data, that is to say, the display conversion of enumeration type is essentially the forced conversion of integer data.

4. Explicit nullable type conversion

Explicit nullable type conversion means that if one value type S can be explicitly converted to another value type T, the following explicit conversions exist for S and T:

    1,S? Can be explicitly converted to T?,If S?The value of is null,So after conversion T?Also null,Otherwise equivalent to S?->S->T->T? Process of
    2,S Can be explicitly converted to T?,This is equivalent to S->T->T? Process of
    3,S? Can be explicitly converted to T,If S?The value of is null,Will be thrown System.InvalidOperationException,Otherwise equivalent to S->T Process of

5. Explicit reference conversion

Explicit reference transformations include:

    1,object and dynamic You can convert an explicit reference to any other reference type
    2,The base class (parent class) can be converted into a subclass by explicit reference
    3,Any non sealed A class can be converted to any interface by explicit reference, regardless of whether the class implements the interface or not
    4,Any interface can be converted to any non interface by explicit reference sealed Class, whether or not the class implements the interface
    5,Any interface can be converted to any interface by explicit reference, whether they are parent-child interface or not
    6,If there is an explicit reference conversion between any two reference types, the arrays of the same dimension can also be converted by explicit reference
    7,System.Array That is, the interface it implements(as System.Collections.IList),You can convert an explicit reference to any array type
    8,If a type S To another type T If there is an explicit reference transformation, then S One dimensional array of S[]reach System.Collections.Generic.IList<T>And its parent interface (e.g System.Collections.Generic.ICollection<T>)There are also explicit reference transformations
    9,If a type S To another type T If there is an explicit reference transformation, then System.Collections.Generic.IList<S>And its parent interface (e.g System.Collections.Generic.ICollection<S>)reach T One dimensional array of T[]There are also explicit reference transformations
    10,System.Delegate And all the interfaces it implements can be explicitly referenced and converted to any delegate type
    11,If a reference type T1 There is an explicit reference conversion to a reference type T2,T2 Existence ID conversion to T3,that T1 You can also convert to by explicit reference T3
    12,If a reference type T1 There is an explicit reference to convert to an interface or delegate type T2,and T2 And T3 There is covariance, inversion or invariance between, then T1 You can also convert to by explicit reference T3
    14,If D<X1,X2,...,Xn>Is a generic delegate type when Xi If one of the following conditions is met, then D<S1,S2...Sn>reach D<T1,T2...Tn>There are explicit reference transformations:
        Xi Is constant, and Si reach Ti identical
        Xi Is covariant, and Si reach Ti There are explicit and implicit identity or reference transformations
        Xi Yes, and Si and Ti Either the same or both reference types

Simple example:

    public class Parent { }
    public class Child : Parent { }
    public interface IPerson { }
    public interface IAnimal { }
    
    object obj = null;
    Parent parent = (Parent)obj;            //object and dynamic You can convert an explicit reference to any other reference type
    Child child = (Child)parent;            //The base class (parent class) can be converted into a subclass by explicit reference
    IPerson person = (IPerson)child;        //Any non sealed A class can be converted to any interface by explicit reference, regardless of whether the class implements the interface or not
    Exception exception = (Exception)person;//Any interface can be converted to any non interface by explicit reference sealed Class, whether or not the class implements the interface
    IAnimal animal = (IAnimal)person;       //Any interface can be converted to any interface by explicit reference, whether they are parent-child interface or not
    
    //If there is an explicit reference conversion between any two reference types, the arrays of the same dimension can also be converted by explicit reference
    IAnimal[] animals = (IAnimal[])new IPerson[0];
    IPerson[,] persons = (IPerson[,])new IAnimal[1, 2];
    
    //System.Array That is, the interface it implements(as System.Collections.IList),You can convert an explicit reference to any array type
    Array array = null;
    IList list = null;
    int[] ints = (int[])array;
    double[,] doubles = (double[,])list;
    
    //If a type S To another type T If there is an explicit reference transformation, then S One dimensional array of S[]reach System.Collections.Generic.IList<T>And its parent interface (e.g System.Collections.Generic.ICollection<T>)There are also explicit reference transformations
    Parent[] parents = null;
    IList<Child> children = (IList<Child>)parents;
    ICollection<Child> children1 = (ICollection<Child>)parents;
    //And vice versa: if a type S To another type T If there is an explicit reference transformation, then System.Collections.Generic.IList<S>And its parent interface (e.g System.Collections.Generic.ICollection<S>)reach T One dimensional array of T[]There are also explicit reference transformations
    parents = (Parent[])children;
    parents = (Parent[])children1;
    
    //System.Delegate And all the interfaces it implements can be explicitly referenced and converted to any delegate type
    Delegate @delegate = null;
    ICloneable cloneable = null;
    Func<int> func = (Func<int>)@delegate;
    Action action = (Action)cloneable;
    
    //If a reference type T1 There is an explicit reference to convert to an interface or delegate type T2,and T2 And T3 There is covariance, inversion or invariance between, then T1 You can also convert to by explicit reference T3
    Array array1 = new Child[0];
    IEnumerable<Parent> parents1 = (IEnumerable<Parent>)array1;//System.Array You can convert an explicit reference to Child[],and Child[]reach IEnumerable<Parent>There is covariance
    
    //If D<X1,X2,...,Xn>Is a generic delegate type when Xi If one of the following conditions is met, then D<S1,S2...Sn>reach D<T1,T2...Tn>There are explicit reference transformations:
    //Xi Is constant, and Si reach Ti identical
    //Xi Is covariant, and Si reach Ti There are explicit and implicit identity or reference transformations
    //Xi Yes, and Si and Ti Either the same or both reference types
    Func<Parent, Child> func1 = p => (Child)p;
    Func<Child, Parent> func2 = (Func<Child, Parent>)func1;

Note: because the explicit reference conversion is checked at run time, we try to ensure that the value to be converted is null or convertible, otherwise system. Will be thrown InvalidCastException

6. Unpacking and conversion

Boxing conversion allows you to package a value type into a reference type for use. On the contrary, unpacking conversion unpacks the reference type to get the value type inside. At present, unpacking conversion includes:

    1,object Can be unpacked and converted to value type
    2,System.ValueType Can be unpacked and converted to any value type.
    3,Any interface can be unpacked and converted to a non null value type that implements this interface
    4,Any interface can be unpacked and converted to an nullable type that implements the value type of the interface
    5,System.Enum Can be unpacked and converted to any enumeration type
    6,System.Enum Nullable types that can be unpacked and converted to any enumerated type

For example

    object obj = 1;
    ValueType value = 2L;
    int i = (int)obj;          //object Can be unpacked and converted to value type
    long l = (long)value;      //System.ValueType Can be unpacked and converted to any value type
    
    IFormattable formattable = 3.14f;
    float s = (float)formattable;           //Any interface can be unpacked and converted to a non null value type that implements this interface
    float? nullable_s = (float?)formattable;//Any interface can be unpacked and converted to an nullable type that implements the value type of the interface
    
    Enum @enum = DayOfWeek.Monday;
    DayOfWeek dayOfWeek1 = (DayOfWeek)@enum;    //System.Enum Can be unpacked and converted to any enumeration type
    DayOfWeek? dayOfWeek2 = (DayOfWeek?)@enum;  //System.Enum Nullable types that can be unpacked and converted to any enumerated type

Note: because the unpacking conversion is checked at runtime, we should try our best to ensure that it is unpackable. If a null value is unpacked to a non empty value object, system. Will be thrown Nullreferenceexception. If the unpacked value is not the appropriate type, system. Exception will be thrown InvalidCastException.

7. Explicit dynamic conversion

Explicit dynamic conversion means that dynamic can be explicitly converted to any other type. It should be noted that it checks the conversion at runtime. If the conversion fails, an exception will be thrown.

    dynamic @dynamic = 3.14f;
    long l = (long)@dynamic;//Can be explicitly and dynamically converted
    int i = @dynamic;//An error will be reported during operation, float Cannot be implicitly converted to int

Generally, if the type saved by the dynamic object is not the required type, it will first convert the dynamic to the object, and then convert the object to the required type. That is, if type S can be explicitly converted to T, then S can also be explicitly converted to T.

8. Explicit conversion involving type parameters

This generally refers to the conversion of generic parameters. In fact, explicit conversion works on generic types. Refer to the following examples:

    public class Parent
    {
        public static explicit operator string(Parent parent) => parent?.ToString();
    }
    public class Demo
    {
        public int E<T>(T t)
        {
            return (int)t;//An error was reported because the generic type is not known T What type is it
        }
        public int F<T>(T t)
        {
            return (int)(object)t;//You can write this without reporting an error
        }
        public string G<T>(T t) where T : Parent
        {
            return (string)t;//Can be converted, Parent Class has custom conversion to string
        }
    
    }

9. User defined explicit conversion

C # allows users to customize the conversion of types or structures. You can see: C# custom transformation (implicit or explicit)

 

Reference documents: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/conversions#explicit-conversions

 

Keywords: C#

Added by vargadanis on Mon, 03 Jan 2022 03:45:24 +0200