Programing

캐스팅과 변환의 차이점은 무엇입니까?

lottogame 2020. 11. 10. 07:40
반응형

캐스팅과 변환의 차이점은 무엇입니까?


이 질문에 이미 답변이 있습니다.

이 질문에 대한 Eric Lippert의 의견은 저를 완전히 혼란스럽게했습니다. C #에서 캐스팅과 변환의 차이점은 무엇입니까?


저는 Eric이 말하려는 것이 다음과 같습니다.

캐스팅 은 구문을 설명하는 용어입니다 (따라서 구문 적 의미).

변환 은 실제로 어떤 작업이 무대 뒤에서 수행되는지 (따라서 의미 론적 의미)를 설명하는 용어 입니다.

캐스트 표현식은 표현식을 지정된 유형으로 명시 적으로 변환하는 데 사용됩니다.

(T) E 형식의 캐스트 식 (T는 형식이고 E는 단항 식)은 E 값을 T 형식으로 명시 적으로 변환 (§13.2)합니다.

구문의 캐스트 연산자가 명시 적 변환을 수행한다고 말함으로써이를 뒷받침하는 것 같습니다.


캐스팅은 컴파일러에게 "오브젝트 X는 실제로 유형 Y입니다. 계속해서 그렇게 취급하십시오."라고 말하는 방법입니다.

변환은 "오브젝트 X가 Y 유형이 아니라는 것을 알고 있지만 X 유형 Y에서 새 객체를 생성하는 방법이 있습니다. 계속 진행하십시오."


나는 Richard Feynman이 철학 수업에 참석하고있는 곳에서 말한 일화가 생각납니다. 그리고 교수는 그에게 "파인만, 당신은 물리학 자입니다. 당신의 의견으로는 전자가 '필수 대상'입니까?"라고 물었습니다. 그래서 파인만은 "벽돌이 필수 대상인가?"라는 명확한 질문을 던집니다. 수업에. 모든 학생은 그 질문에 대해 다른 답을 가지고 있습니다. 그들은 "벽돌"의 근본적 추상 개념이 본질적인 대상이라고 말합니다. 아니요, 하나의 특정하고 고유 한 벽돌이 필수 개체입니다. 아니요, 경험적으로 관찰 할 수있는 벽돌 부분이 필수 대상입니다. 등등.

물론 귀하의 질문에 대답하지 않습니다.

나는이 12 개의 답을 모두 검토하고 내가 정말로 의미하는 바에 대해 그들의 저자들과 토론하지 않을 것입니다. 나는 몇 주 안에 주제에 대한 블로그 기사를 쓸 것이고 그것이 문제에 대해 어떤 빛을 던지는 지 볼 것입니다.

하지만 비유는 어떨까요, a la Feynman. 토요일 아침에 바나나 빵 한 덩어리를 굽고 싶습니다 (거의 매주 토요일 아침에합니다.) The Joy of Cooking에 문의하면 "blah blah blah ... 다른 그릇에 마른 재료를 함께 휘젓습니다.. .. "

분명히 그 지시와 내일 아침 당신의 행동 사이에는 강한 관계가 있지만, 그 지시행동합치는 것도 똑같이 실수 일 것 입니다. 지침은 텍스트로 구성됩니다. 특정 페이지에 위치가 있습니다. 구두점이 있습니다. 부엌에서 밀가루와 베이킹 소다를 함께 휘젓고 누군가가 "지금 당신의 구두점은 무엇입니까?"라고 물었다면 아마 이상한 질문이라고 생각했을 것입니다. 작업은 지침과 관련이 있지만 지침의 텍스트 속성은 작업의 속성이 아닙니다.

캐스트는 레시피가 케이크를 굽는 행위가 아닌 것과 같은 방식으로 전환이 아닙니다. 레시피는 수행 할 수있는 작업을 설명하는 텍스트입니다. 캐스트 연산자는 런타임이 수행 할 수있는 작업 (변환)을 설명하는 텍스트입니다.


C # Spec 14.6.6에서 :

캐스트 표현식은 표현식을 지정된 유형으로 명시 적으로 변환하는 데 사용됩니다.
...
(T) E 형식의 캐스트 식 (T는 형식이고 E는 단항 식)은 E 값을 T 형식으로 명시 적으로 변환 (§13.2)합니다.

따라서 캐스팅은 명시 적 변환을 호출하도록 컴파일러에 지시하는 데 사용되는 구문 구조입니다.

C # 사양 §13에서 :

변환을 통해 한 유형의 표현식을 다른 유형으로 처리 할 수 ​​있습니다. 변환은 암시 적이거나 명시적일 수 있으며 이는 명시 적 캐스트가 필요한지 여부를 결정합니다. [예 : int 유형에서 long 유형으로의 변환은 암시 적이므로 int 유형의 표현식은 암시 적으로 long 유형으로 처리 될 수 있습니다. long 형식에서 int 형식으로의 반대 변환은 명시 적이므로 명시 적 캐스트가 필요합니다.

따라서 변환은 실제 작업이 수행되는 곳입니다. cast-expression 따옴표는 명시 적 변환을 수행하지만 명시 적 변환은 암시 적 변환의 상위 집합이므로 캐스트 식을 통해 암시 적 변환을 호출 할 수도 있습니다 (필요하지 않은 경우에도).


내 이해, 아마도 너무 간단합니다.

캐스트 할 때 필수 데이터는 그대로 유지됩니다 (동일한 내부 표현)- "사전이라는 것을 알고 있지만 ICollection으로 사용할 수 있습니다."

변환 할 때 내부 표현을 "I want this int to be string"으로 변경합니다.


Eric의 의견을 읽은 후 평범한 영어로 시도했습니다.

캐스팅 은 두 유형이 실제로 어떤 수준에서 동일하다는 것을 의미합니다. 동일한 인터페이스를 구현하거나 동일한 기본 클래스에서 상속하거나 Int16에서 Int32로 캐스팅하는 것과 같이 캐스트가 작동하도록 대상이 "충분히 동일"(상위 집합?) 될 수 있습니다.

그런 다음 유형 변환 은 두 개체가 변환 될 수있을만큼 유사 할 수 있음을 의미합니다. 예를 들어 숫자의 문자열 표현을 사용하십시오. 그것은 문자열이고, 단순히 숫자로 형변환 될 수 없으며, 파싱되고 하나에서 다른 것으로 변환되어야하며, 프로세스가 실패 할 수 있습니다. 캐스팅에도 실패 할 수 있지만 훨씬 저렴한 실패라고 생각합니다.

이것이 제가 생각하는 두 개념의 주요 차이점입니다. 변환에는 일종의 구문 분석 또는 소스 데이터의 심층 분석 및 변환이 수반됩니다. 캐스팅은 구문 분석하지 않습니다. 단순히 다형성 수준에서 일치를 시도합니다.


캐스팅 은 다른 유형의 다른 값에서 한 유형의 값을 생성하는 것입니다. 변환 은 값의 내부 표현도 변경되어야하는 캐스팅 유형입니다 (단순한 해석이 아님).

C #에서 캐스팅과 변환은 모두 cast-expression으로 수행됩니다 .

( 유형 ) 단항식

conversion-operator-declarator에 의해 변환 만 생성 될 수 있기 때문에 구별이 중요합니다 (주석에 요점이 있습니다) . 따라서 코드에서 (암시 적 또는 명시 적) 변환 만 만들 수 있습니다.

비 변환 암시 적 캐스트는 항상 하위 유형 대 상위 유형 캐스트에 사용할 수 있으며 비 변환 명시 적 캐스트는 항상 상위 유형 대 하위 유형 캐스트에 사용할 수 있습니다. 다른 비 전환 캐스트는 허용되지 않습니다.


이 맥락에서 캐스팅은 조작을 위해 주어진 유형의 객체를 다른 유형으로 노출하는 것을 의미하고, 변환은 실제로 주어진 유형의 객체를 다른 유형의 객체로 변경하는 것을 의미합니다.


MSDN C # 문서 의이 페이지 에서는 캐스트가 "명시 적 변환"이라는 특정 변환 인스턴스임을 제안합니다. 즉, 형식의 변환은 x = (int)y캐스트입니다.

자동 데이터 유형 변경 (예 myLong = myInt:)은보다 일반적인 "변환"입니다.


캐스트는 클래스 / 구조체에 대한 연산자입니다. 변환은 영향을받는 클래스 / 구조체 중 하나 또는 다른 하나에 대한 메서드 / 프로세스이거나 완전히 다른 클래스 / 구조체 (예 :Converter.ToInt32()

캐스트 연산자는 암시 적 및 명시 적 두 가지 유형으로 제공됩니다.

암시 적 캐스트 연산자는 한 유형 (예 : Int32) 의 데이터가 데이터 / 정밀도 손실없이 항상 다른 유형 (10 진수)으로 표현 될 있음을 나타냅니다 .

int i = 25;
decimal d = i;

명시 적 캐스트 연산자는 한 유형 (10 진수)의 데이터가 항상 다른 유형 (int)으로 충실하게 표현 될 수 있지만 데이터 / 정밀도가 손실 될 수 있음을 나타냅니다. 컴파일러는 당신을 필요로 이에 대한 명시 적으로 당신이 알고 있으며 명시 적 캐스트 구문의 사용을 통해, 어쨌든 그것을 할 것인지 상태 :

decimal d = 25.0001;
int i = (int)d;

변환은 반드시 어떤 식 으로든 관련이없는 두 가지 유형을 취하고 구문 분석과 같은 일부 프로세스를 통해 하나를 다른 유형으로 변환하려고 시도합니다. 알려진 모든 변환 알고리즘이 실패하면 프로세스가 예외를 발생 시키거나 기본값을 반환 할 수 있습니다.

string s = "200";
int i = Converter.ToInt32(s); // set i to 200 by parsing s

string s = "two hundred";
int i = Converter.ToInt32(s); // sets i to 0 because the parse fails

구문 변환 대 시맨틱 변환에 대한 Eric의 언급은 기본적으로 연산자 대 방법론의 차이입니다.


캐스트는 구문 적이며 변환을 포함하거나 포함하지 않을 수 있습니다 (캐스트 유형에 따라 다름). 아시다시피 C ++에서는 사용하려는 캐스트 유형을 지정할 수 있습니다.

계층 구조를 위 / 아래로 캐스팅하는 것은 질문하는 사람 (및 그들이 말하는 언어) 에 따라 전환으로 간주 될 수도 있고 그렇지 않을 수도 있습니다 .

Eric (C#) is saying that casting to a different type always involves a conversion, though that conversion may not even change the internal representation of the instance.

A C++-guy will disagree, since a static_cast might not result in any extra code (so the "conversion" is not actually real!)


Casting and Conversion are basically the same concept in C#, except that a conversion may be done using any method such as Object.ToString(). Casting is only done with the casting operator (T) E, that is described in other posts, and may make use of conversions or boxing.

Which conversion method does it use? The compiler decides based on the classes and libraries provided to the compiler at compile-time. If an implicit conversion exists, you are not required to use the casting operator. Object o = String.Empty. If only explicit conversions exist, you must use the casting operator. String s = (String) o.

You can create explicit and implicit conversion operators in your own classes. Note: conversions can make the data look very similar or nothing like the original type to you and me, but it's all defined by the conversion methods, and makes it legal to the compiler.

Casting always refers to the use of the casting operator. You can write

Object o = float.NaN;
String s = (String) o;

But if you access s, in for example a Console.WriteLine, you will receive a runtime InvalidCastException. So, the cast operator still attempts to use conversion at access time, but will settle for boxing during assignment.


INSERTED EDIT#2: isn't it hilariously inconsistent myopia that since I provided this answer, the question has been marked as duplicate of a question which asks, "Is casting the same thing as converting?". And the answers of "No" are overwhelmingly upvoted. Yet my answer here which points out the generative essence for why casts are not the same as conversion is overwhelmingly downvoted (yet I have one +1 in the comments). I suppose that readers have a difficult time with comprehending that casts apply at the denotational syntax/semantics layer and conversions apply at the operational semantics layer. For example, a cast of a reference (or pointer in C/C++)—referring to a boxed data type—to another data type, doesn't (in all languages and scenarios) generate a conversion of the boxed data. For example, in C float a[1]; int* p = (int*)&a; doesn't insure that *p refers to int data.

A compiler compiles from denotational semantics to operational semantics. The compilation is not bijective, i.e. it isn't guaranteed to uncompile (e.g. Java, LLVM, asm.js, or C# bytecode) back to any denotational syntax which compiles to that bytecode (e.g. Scala, Python, C#, C via Emscripten, etc). Thus the two layers not the same.

Thus most obviously a 'cast' and a 'conversion' are not the same thing. My answer here is pointing out that the terms apply to two different layers of semantics. Casts apply to the semantics of what the denotational layer (input syntax of the compiler) knows about. Conversions apply to the semantics of what the operational (runtime or intermediate bytecode) layer knows about. I used the standard term of 'erased' to describe what happens to denotational semantics that aren't explicitly recorded in the operational semantics layer.

For example, reified generics are an example of recording denotational semantics in the operational semantics layer, but they have the disadvantage of making the operational semantics layer incompatible with higher-order denotational semantics, e.g. this is why it was painful to consider implementing Scala's higher-kinded generics on C#'s CLR because C#'s denotational semantics for generics was hard-coded at the operational semantics layer.

Come on guys, stop downvoting someone who knows a lot more than you do. Do your homework first before you vote.


INSERTED EDIT: Casting is an operation that happens at the denotational semantics layer (where types are expressed in their full semantics). A cast may (e.g. explicit conversion) or may not (e.g. upcasting) cause a conversion at the runtime semantic layer. The downvotes on my answer (and the upvoting on Marc Gavin's comment) indicates to me that most people don't understand the differences between denotational semantics and operational (execution) semantics. Sigh.


I will state Eric Lippert's answer more simply and more generally for all languages, including C#.

A cast is syntax so (like all syntax) is erased at compile-time; whereas, a conversion causes some action at runtime.


That is a true statement for every computer language that I am aware of in the entire universe. Note that the above statement does not say that casting and conversions are mutually exclusive.

A cast may cause a conversion at runtime, but there are cases where it may not.

The reason we have two distinct words, i.e. cast and conversion, is we need a way to separately describe what is happening in syntax (the cast operator) and at runtime (conversion, or type check and possible conversion).

It is important that we maintain this separation-of-concepts, because in some programming languages the cast never causes a conversion. Also so that we understand implicit casting (e.g. upcasting) is happening only at compile-time. The reason I wrote this answer is because I want to help readers understand in terms of being multilingual with computer languages. And also to see how that general definition correctly applies in the C# case as well.

Also I wanted to help readers see how I generalize concepts in my mind, which helps me as computer language designer. I am trying to pass along the gift of a very reductionist, abstract way of thinking. But I am also trying to explain this in a very practical way. Please feel free to let me know in the comments if I need to improve the elucidation.


Eric Lippert wrote:

A cast is not a conversion in the same way that a recipe is not the act of baking a cake. A recipe is text which describes an action, which you can then perform. A cast operator is text which describes an action - a conversion - which the runtime can then perform.

The recipe is what is happening in syntax. Syntax is always erased, and replaced with either nothing or some runtime code.

For example, I can write a cast in C# that does nothing and is entirely erased at compile-time when it is does not cause a change in the storage requirements or is upcasting. We can clearly see that a cast is just syntax, that makes no change to the runtime code.

int x = 1;
int y = (int)x;
Giraffe g = new Giraffe();
Animal a = (Animal)g;

That can be used for documentation purposes (yet noisy), but it is essential in languages that have type inference, where a cast is sometimes necessary to tell the compiler what type you wish it to infer.

For an example, in Scala a None has the type Option[Nothing] where Nothing is the bottom type that is the sub-type of all possible types (not super-type). So sometimes when using None, the type needs to be casted to a specific type, because Scala only does local type inference, thus can't always infer the type you intended.

// (None : Option[Int]) casts None to Option[Int]
println(Some(7) <*> ((None : Option[Int]) <*> (Some(9) > add)))

A cast could know at compile-time that it requires a type conversion, e.g. int x = (int)1.5, or could require a type check and possible type conversion at runtime, e.g. downcasting. The cast (i.e. the syntax) is erased and replaced with the runtime action.

Thus we can clearly see that equating all casts with explicit conversion, is an error of implication in the MSDN documentation. That documentation is intending to say that explicit conversion requires a cast operator, but it should not be trying to also imply that all casts are explicit conversions. I am confident that Eric Lippert can clear this up when he writes the blog he promised in his answer.


ADD: From the comments and chat, I can see that there is some confusion about the meaning of the term erased.

The term 'erased' is used to describe information that was known at compile-time, which is not known at runtime. For example, types can be erased in non-reified generics, and it is called type erasure.

Generally speaking all the syntax is erased, because generally CLI is not bijective (invertible, and one-to-one) with C#. You cannot always go backwards from some arbitrary CLI code back to the exact C# source code. This means information has been erased.

Those who say erased is not the right term, are conflating the implementation of a cast with the semantic of the cast. The cast is a higher-level semantic (I think it is actually higher than syntax, it is denotational semantics at least in case of upcasting and downcasting) that says at that level of semantics that we want to cast the type. Now how that gets done at runtime is entirely different level of semantics. In some languages it might always be a NOOP. For example, in Haskell all typing information is erased at compile-time.

참고URL : https://stackoverflow.com/questions/3166840/what-is-the-difference-between-casting-and-conversion

반응형