Direct casting vs 'as' operator?

后端 未结 16 1742
独厮守ぢ
独厮守ぢ 2020-11-22 01:43

Consider the following code:

void Handler(object o, EventArgs e)
{
   // I swear o is a string
   string s = (string)o; // 1
   //-OR-
   string s = o as str         


        
相关标签:
16条回答
  • 2020-11-22 02:17

    'as' is based on 'is', which is a keyword that checks at runtime if the object is polimorphycally compatible (basically if a cast can be made) and returns null if the check fails.

    These two are equivalent:

    Using 'as':

    string s = o as string;
    

    Using 'is':

    if(o is string) 
        s = o;
    else
        s = null;
    

    On the contrary, the c-style cast is made also at runtime, but throws an exception if the cast cannot be made.

    Just to add an important fact:

    The 'as' keyword only works with reference types. You cannot do:

    // I swear i is an int
    int number = i as int;
    

    In those cases you have to use casting.

    0 讨论(0)
  • 2020-11-22 02:17

    Since nobody mentioned it, the closest to instanceOf to Java by keyword is this:

    obj.GetType().IsInstanceOfType(otherObj)
    
    0 讨论(0)
  • 2020-11-22 02:17

    Use direct cast string s = (string) o; if in the logical context of your app string is the only valid type. With this approach, you will get InvalidCastException and implement the principle of Fail-fast. Your logic will be protected from passing the invalid type further or get NullReferenceException if used as operator.

    If the logic expects several different types cast string s = o as string; and check it on null or use is operator.

    New cool feature have appeared in C# 7.0 to simplify cast and check is a Pattern matching:

    if(o is string s)
    {
      // Use string variable s
    }
    
    or
    
    switch (o)
    {
      case int i:
         // Use int variable i
         break;
      case string s:
         // Use string variable s
         break;
     }
    
    0 讨论(0)
  • 2020-11-22 02:20

    It seems the two of them are conceptually different.

    Direct Casting

    Types don't have to be strictly related. It comes in all types of flavors.

    • Custom implicit/explicit casting: Usually a new object is created.
    • Value Type Implicit: Copy without losing information.
    • Value Type Explicit: Copy and information might be lost.
    • IS-A relationship: Change reference type, otherwise throws exception.
    • Same type: 'Casting is redundant'.

    It feels like the object is going to be converted into something else.

    AS operator

    Types have a direct relationship. As in:

    • Reference Types: IS-A relationship Objects are always the same, just the reference changes.
    • Value Types: Copy boxing and nullable types.

    It feels like the you are going to handle the object in a different way.

    Samples and IL

        class TypeA
        {
            public int value;
        }
    
        class TypeB
        {
            public int number;
    
            public static explicit operator TypeB(TypeA v)
            {
                return new TypeB() { number = v.value };
            }
        }
    
        class TypeC : TypeB { }
        interface IFoo { }
        class TypeD : TypeA, IFoo { }
    
        void Run()
        {
            TypeA customTypeA = new TypeD() { value = 10 };
            long longValue = long.MaxValue;
            int intValue = int.MaxValue;
    
            // Casting 
            TypeB typeB = (TypeB)customTypeA; // custom explicit casting -- IL:  call class ConsoleApp1.Program/TypeB ConsoleApp1.Program/TypeB::op_Explicit(class ConsoleApp1.Program/TypeA)
            IFoo foo = (IFoo)customTypeA; // is-a reference -- IL: castclass  ConsoleApp1.Program/IFoo
    
            int loseValue = (int)longValue; // explicit -- IL: conv.i4
            long dontLose = intValue; // implict -- IL: conv.i8
    
            // AS 
            int? wraps = intValue as int?; // nullable wrapper -- IL:  call instance void valuetype [System.Runtime]System.Nullable`1<int32>::.ctor(!0)
            object o1 = intValue as object; // box -- IL: box [System.Runtime]System.Int32
            TypeD d1 = customTypeA as TypeD; // reference conversion -- IL: isinst ConsoleApp1.Program/TypeD
            IFoo f1 = customTypeA as IFoo; // reference conversion -- IL: isinst ConsoleApp1.Program/IFoo
    
            //TypeC d = customTypeA as TypeC; // wouldn't compile
        }
    
    0 讨论(0)
提交回复
热议问题