Program Tip

직접 캐스팅 대 'as'연산자?

programtip 2020. 9. 30. 11:21
반응형

직접 캐스팅 대 'as'연산자?


다음 코드를 고려하십시오.

void Handler(object o, EventArgs e)
{
   // I swear o is a string
   string s = (string)o; // 1
   //-OR-
   string s = o as string; // 2
   // -OR-
   string s = o.ToString(); // 3
}

세 가지 유형의 캐스팅의 차이점은 무엇입니까 (좋아, 세 번째 캐스팅은 캐스팅이 아니지만 의도를 얻습니다). 어느 것이 선호되어야합니까?


string s = (string)o; // 1

예외 InvalidCastException이를 경우 o하지 않은 것입니다 string. 그렇지 않으면, 양수인 os, 경우에도이 o있다 null.

string s = o as string; // 2

를 할당 null하는 s경우 o없는 string경우, 또는 o이다 null. 이러한 이유로 값 유형과 함께 사용할 수 없습니다 (이 경우 연산자는 반환 할 수 없습니다 null). 그렇지 않으면에 할당 o합니다 s.

string s = o.ToString(); // 3

원인 NullReferenceException이 있는 경우 o입니다 null. 유형 무엇 이든 상관없이 o.ToString()반환 값을에 할당 합니다 .so


대부분의 전환에 1을 사용합니다. 간단하고 간단합니다. 나는 어떤 것이 올바른 유형이 아니면 보통 예외가 발생할 것으로 예상하기 때문에 2를 거의 사용하지 않는 경향이 있습니다. 오류 코드를 사용하는 잘못 설계된 라이브러리 (예 : 예외를 사용하는 대신 null = 오류를 반환)를 사용하여이 반환 null 유형의 기능이 필요하다는 것만 보았습니다.

3은 캐스트가 아니며 메소드 호출 일뿐입니다. 문자열이 아닌 객체의 문자열 표현이 필요할 때 사용합니다.


  1. string s = (string)o;어떤 것이 확실히 다른 것이 되어야 할 때 사용하십시오 .
  2. string s = o as string;다른 것이 있을 때 사용하십시오 .
  3. string s = o.ToString(); 그것이 무엇인지 신경 쓰지 않지만 사용 가능한 문자열 표현을 사용하고 싶을 때 사용하십시오.

실제로 o문자열 인지 여부 와 그로 무엇을 할 것인지에 달려 있습니다. 귀하의 의견이 o실제로 문자열 이라는 것을 의미한다면 , 나는 스트레이트 (string)o캐스트를 선호합니다 . 실패 할 가능성은 거의 없습니다.

스트레이트 캐스트를 사용하는 가장 큰 장점은 실패 할 때 잘못된 것이 무엇인지 거의 알려주 InvalidCastException 이 발생한다는 것입니다.

as연산자를 사용하면 o문자열이 아닌 경우 s설정됩니다 null. 확실하지 않고 테스트하려는 경우 유용합니다 s.

string s = o as string;
if ( s == null )
{
    // well that's not good!
    gotoPlanB();
}

그러나 해당 테스트를 수행하지 않으면 s나중에 사용 하고 NullReferenceException이 발생합니다. 거의 모든 줄이 변수를 역 참조하고 하나를 던질 수 있기 때문에 이들은 야생에서 발생하면 더 일반적이며 추적하기가 훨씬 더 어렵습니다. 반면에 값 유형 (모든 프리미티브 또는 DateTime 과 같은 구조체 )으로 캐스트하려는 경우 스트레이트 캐스트를 사용해야합니다 as. 작동하지 않습니다.

문자열로 변환하는 특별한 경우에는 모든 객체에이 ToString있으므로 onull이 아니고 ToString메서드가 원하는 작업을 수행 할 수 있다고 생각하면 세 번째 메서드가 괜찮을 수 있습니다 .


캐스트 할 수있는 유형을 이미 알고있는 경우 C 스타일 캐스트를 사용하십시오.

var o = (string) iKnowThisIsAString; 

C 스타일 캐스트에서만 명시 적 유형 강제 변환을 수행 할 수 있습니다.

이 원하는 형식이고 당신이 그것을 사용하는 경우이를 사용하려고하고 있는지 당신이 모르는 경우 등의 키워드 :

var s = o as string;
if (s != null) return s.Replace("_","-");

//or for early return:
if (s==null) return;

참고 모든 종류의 변환 연산자를 호출하지 않습니다. 개체가 null이 아니고 기본적으로 지정된 유형 인 경우에만 null이 아닙니다.

ToString ()을 사용하여 문자열로 캐스트 할 수없는 경우에도 사람이 읽을 수있는 모든 개체의 문자열 표현을 가져옵니다.


as 키워드는 FindControl 메서드를 사용할 때 asp.net에서 좋습니다.

Hyperlink link = this.FindControl("linkid") as Hyperlink;
if (link != null)
{
     ...
}

object, 직접 캐스트를 사용하는 것처럼 캐스트해야하는 대신 유형이 지정된 변수에 대해 작업 할 수 있습니다 .

object linkObj = this.FindControl("linkid");
if (link != null)
{
     Hyperlink link = (Hyperlink)linkObj;
}

큰 것은 아니지만 코드 줄과 변수 할당을 절약하고 더 읽기 쉽습니다.


'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.


2 is useful for casting to a derived type.

Suppose a is an Animal:

b = a as Badger;
c = a as Cow;

if (b != null)
   b.EatSnails();
else if (c != null)
   c.EatGrass();

will get a fed with a minimum of casts.


According to experiments run on this page: http://www.dotnetguru2.org/sebastienros/index.php/2006/02/24/cast_vs_as

(this page is having some "illegal referrer" errors show up sometimes, so just refresh if it does)

Conclusion is, the "as" operator is normally faster than a cast. Sometimes by many times faster, sometimes just barely faster.

I peronsonally thing "as" is also more readable.

So, since it is both faster and "safer" (wont throw exception), and possibly easier to read, I recommend using "as" all the time.


"(string)o" will result in an InvalidCastException as there's no direct cast.

"o as string" will result in s being a null reference, rather than an exception being thrown.

"o.ToString()" isn't a cast of any sort per-se, it's a method that's implemented by object, and thus in one way or another, by every class in .net that "does something" with the instance of the class it's called on and returns a string.

Don't forget that for converting to string, there's also Convert.ToString(someType instanceOfThatType) where someType is one of a set of types, essentially the frameworks base types.


All given answers are good, if i might add something: To directly use string's methods and properties (e.g. ToLower) you can't write:

(string)o.ToLower(); // won't compile

you can only write:

((string)o).ToLower();

but you could write instead:

(o as string).ToLower();

The as option is more readable (at least to my opinion).


string s = o as string; // 2

Is prefered, as it avoids the performance penalty of double casting.


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
    }

I would like to attract attention to the following specifics of the as operator:

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/as

Note that the as operator performs only reference conversions, nullable conversions, and boxing conversions. The as operator can't perform other conversions, such as user-defined conversions, which should instead be performed by using cast expressions.


When trying to get the string representation of anything (of any type) that could potentially be null, I prefer the below line of code. It's compact, it invokes ToString(), and it correctly handles nulls. If o is null, s will contain String.Empty.

String s = String.Concat(o);

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

obj.GetType().IsInstanceOfType(otherObj)

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;
 }

The following two forms of type conversion (casting) is supported in C#:

|

(C) v

• Convert the static type of v to c in the given expression

• Only possible if the dynamic type of v is c, or a subtype of c

• If not, an InvalidCastException is thrown

|

v as C

• Non-fatal variant of (c) v

• Thus, convert the static type of v to c in the given expression

• Returns null if the dynamic type of v is not c, or a subtype of c

참고URL : https://stackoverflow.com/questions/132445/direct-casting-vs-as-operator

반응형