[c#] 캐스팅과 Convert.To () 메서드 사용의 차이점

나는 캐스트 기능이 doublestring값을.

string variable = "5.00";

double varDouble = (double)variable;

코드 변경이 체크인되었으며 프로젝트가 오류와 함께 빌드됩니다. System.InvalidCastException: Specified cast is not valid.

그러나 다음을 수행하면 …

string variable = "5.00";

double varDouble = Convert.ToDouble(variable);

… 프로젝트는 오류없이 빌드됩니다.

캐스팅과 Convert.To()방법 사용의 차이점은 무엇입니까 ?캐스팅은 왜 던지고 Exception사용 Convert.To()하지 않습니까?



답변

어떻게 든 동등하다고 볼 있더라도 목적이 완전히 다릅니다. 먼저 캐스트가 무엇인지 정의 해 보겠습니다.

캐스팅은 한 데이터 유형의 엔티티를 다른 유형으로 변경하는 작업입니다.

캐스트는 종종 동일한 변환 구문을 갖기 때문에 약간 일반적이며 변환 과 동일합니다. 그러므로 질문은 언어에서 캐스트 (암시 적 또는 명시 적)를 허용 할 때와 언제 ( 더) 명시 적 변환?

먼저 그들 사이에 간단한 선을 그리 겠습니다 . 형식적으로 (언어 구문과 동일하더라도) 캐스트는 유형을 변경하는 반면 변환은 값을 변경하거나 변경할 수 있습니다 (결국 함께 유형 함께). 또한 캐스트는 되돌릴 수 있지만 변환은 불가능할 수 있습니다.

이 주제는 상당히 방대하므로 게임에서 커스텀 캐스트 연산자를 제외하여 조금 좁혀 보겠습니다.

암시 적 캐스트

C #에서는 정보를 잃지 않을 때 캐스트가 암시 적 입니다 (이 검사는 실제 값이 아닌 형식 으로 수행 됩니다. ).

기본 유형

예를 들면 :

int tinyInteger = 10;
long bigInteger = tinyInteger;

float tinyReal = 10.0f;
double bigReal = tinyReal;

이러한 캐스트는 변환하는 동안 정보를 잃지 않을 것이기 때문에 암시 적입니다 (유형을 더 넓게 만들기 만하면 됨). 그 반대의 경우 암시 적 캐스트는 허용되지 않습니다. 실제 값에 관계없이 (런타임에서만 확인할 수 있기 때문에) 변환 중에 일부 정보가 손실 될 수 있기 때문입니다. 예를 들어이 코드는 다음 double과 같이 표현할 수없는 값을 포함 할 수 있기 때문에 컴파일 되지 않습니다 float.

// won't compile!
double bigReal = Double.MaxValue;
float tinyReal = bigReal;

사물

객체 (에 대한 포인터)의 경우 컴파일러가 소스 유형이 파생 클래스 (또는 대상 클래스의 유형을 구현)인지 확인할 수있을 때 캐스트는 항상 암시 적입니다. 예를 들면 다음과 같습니다.

string text = "123";
IFormattable formattable = text;

NotSupportedException derivedException = new NotSupportedException();
Exception baseException = derivedException;

이 경우 컴파일러는 알고string구현을 IFormattable하고는 NotSupportedException(에서 파생)입니다 Exception캐스트가 암시하므로. 객체가 유형을 변경하지 않기 때문에 정보가 손실되지 않습니다 ( struct캐스트를 사용하면 다른 유형새 객체 를 생성하기 때문에 s 및 기본 유형과 다릅니다 ). 가 변경됩니다. 그들.

명시 적 캐스트

변환이 컴파일러에 의해 암시 적으로 수행되지 않은 경우 캐스트는 명시 적이며 캐스트 연산자를 사용해야합니다. 일반적으로 다음을 의미합니다.

  • 정보 나 데이터를 잃을 수 있으므로 알고 있어야합니다.
  • 변환이 실패 할 수 있습니다 (한 유형을 다른 유형으로 변환 할 수 없기 때문에). 따라서 수행중인 작업을 알고 있어야합니다.

기본 유형

변환 중에 일부 데이터가 손실 될 수있는 경우 기본 유형에 대해 명시 적 캐스트가 필요합니다. 예를 들면 다음과 같습니다.

double precise = Math.Cos(Math.PI * 1.23456) / Math.Sin(1.23456);
float coarse = (float)precise;

float epsilon = (float)Double.Epsilon;

두 예에서 값이 float범위 내에 있더라도 정보 (이 경우 정밀도)가 손실되므로 변환이 명시 적이어야합니다. 이제 이것을 시도하십시오.

float max = (float)Double.MaxValue;

이 변환은 실패하므로 다시 명시 적이어야하며이를인지하고 확인을 수행 할 수 있습니다 (이 예에서는 값이 일정하지만 일부 런타임 계산 또는 I / O에서 올 수 있음). 귀하의 예로 돌아가십시오.

// won't compile!
string text = "123";
double value = (double)text;

컴파일러가 텍스트를 숫자로 변환 할 수 없기 때문에 컴파일되지 않습니다. 텍스트에는 숫자뿐만 아니라 모든 문자가 포함될 수 있으며 C #에서는 명시 적 캐스트의 경우에도 너무 많습니다 (하지만 다른 언어에서는 허용 될 수 있음).

사물

유형이 관련되지 않은 경우 포인터에서 객체로의 변환이 실패 할 수 있습니다. 예를 들어이 코드는 컴파일되지 않습니다 (컴파일러가 가능한 변환이 없음을 알고 있기 때문).

// won't compile!    
string text = (string)AppDomain.Current;
Exception exception = (Exception)"abc";

이 코드는 컴파일되지만 런타임에 실패 할 수 있습니다 (캐스트 된 객체의 유효 유형에 따라 다름) InvalidCastException.

object obj = GetNextObjectFromInput();
string text = (string)obj;

obj = GetNextObjectFromInput();
Exception exception = (Exception)obj;

전환

그래서 마지막으로 캐스트가 변환이라면 왜 우리는 같은 클래스가 필요 Convert합니까? 실제로 Convert구현 및 IConvertible구현 에서 발생하는 미묘한 차이점을 무시하는 것은 C #에서 캐스트를 사용하여 컴파일러에 말하기 때문입니다.

저를 믿으세요.이 타입은 지금은 알 수 없더라도 저런 타입입니다.

-또는-

걱정하지 마세요.이 전환에서 무언가가 손실 되더라도 상관 없습니다.

다른 어떤 경우에는 보다 명시적인 작업이 필요합니다 ( 쉬운 캐스트의 의미에 대해 생각해보십시오. 이것이 C ++에서 길고 장황하며 명시적인 구문을 도입 한 이유입니다). 이것은 복잡한 작업을 포함 할 수 있습니다 ( string-> double변환을 위해 구문 분석이 필요합니다). string예를 들어으로 변환하는 것은 항상 가능합니다 ( ToString()메소드 를 통해 ).하지만 예상과 다른 것을 의미 할 수 있으므로 캐스트보다 더 명시 적이어야합니다 ( 더 많이 작성하고 수행중인 작업에 대해 더 많이 생각합니다. ).

이 변환은 사용자 지정 변환 연산자 (캐스트 할 클래스에 정의 됨) 또는 더 복잡한 메커니즘 ( TypeConverter예 : s 또는 클래스 메서드 )을 사용하여 객체 내에서 수행 할 수 있습니다 (알려진 IL 명령어 사용 ). 어떤 일이 일어날 지 모르지만 실패 할 수 있다는 것을 알고 있습니다 (더 제어 된 변환이 가능할 때 IMO 를 사용해야하는 이유입니다). 귀하의 경우 변환은 단순히을 구문 분석하여 다음 string을 생성합니다 double.

double value = Double.Parse(aStringVariable);

물론 이것은 실패 할 수 있으므로이를 수행하면 항상 예외가 발생할 수 있습니다 ( FormatException). 그것은 여기에 주제에 밖으로이다 그러나이 때 TryParse사용할 수 있습니다 의미 당신이 때문에 당신은 (그것을 사용한다 라고 는 숫자하지 않을 수 있습니다 그것은 실패 …도 빠릅니다).

.NET의 변환은 TypeConverter사용자 정의 변환 연산자를 사용한 암시 적 / 명시 적 캐스트,IConvertible 메서드 및 구문 분석 (내가 잊은 것이 있습니까?) . 이에 대한 자세한 내용은 MSDN을 참조하십시오.

이 긴 대답을 끝내려면 사용자 정의 변환 연산자에 대해 몇 마디 만하면됩니다. 그것은 단지 설탕 프로그래머가 다른 한 가지 유형으로 캐스팅을 사용하게 할 수 있습니다. “이 유형을 해당 유형으로 변환하려면 내가 할 수 있습니다”라고 말하는 클래스 (캐스트 될 것) 내부의 메소드입니다. 예를 들면 :

float? maybe = 10; // Equals to Nullable<float> maybe = 10;
float sure1 = (float)maybe; // With cast
float sure2 = maybe.Value; // Without cast

이 경우 실패 할 수 있기 때문에 명시 적이지만 구현에 맡겨집니다 (이에 대한 지침이 있더라도). 다음과 같은 사용자 지정 문자열 클래스를 작성한다고 가정 해보십시오.

EasyString text = "123"; // Implicit from string
double value = (string)text; // Explicit to double

구현에서 “프로그래머의 삶을 더 쉽게 만들기”를 결정하고 캐스트를 통해이 변환을 노출 할 수 있습니다 (단순히 작성하는 지름길 일뿐임을 기억하십시오). 일부 언어는이를 허용 할 수도 있습니다.

double value = "123";

모든 유형에 대한 암시 적 변환 허용 (확인은 런타임에 수행됨). 적절한 옵션을 사용하면 예를 들어 VB.NET에서이를 수행 할 수 있습니다. 그것은 단지 다른 철학입니다.

그들로 무엇을 할 수 있습니까?

그래서 마지막 질문은 언제 하나 또는 다른 것을 사용해야 하는가입니다. 언제 명시 적 캐스트를 사용할 수 있는지 살펴 보겠습니다.

  • 기본 유형 간의 변환.
  • 전환 object 다른 유형으로의 (개봉도 포함될 수 있음).
  • 파생 클래스에서 기본 클래스 (또는 구현 된 인터페이스) 로의 변환.
  • 사용자 지정 변환 연산자를 통해 한 유형에서 다른 유형으로 변환합니다.

첫 번째 변환 만 수행 할 수 있습니다. Convert 선택의 여지가없고 명시 적 캐스트를 사용해야합니다.

이제 언제 사용할 수 있는지 보겠습니다 Convert.

  • 모든 기본 유형에서 다른 기본 유형으로의 변환 (몇 가지 제한 사항이 있음, MSDN 참조 ).
  • IConvertible다른 (지원되는) 유형으로 구현되는 모든 유형에서 변환 .
  • byte배열에서 문자열로 /에서 변환 .

결론

Convert변환이 실패 할 수 있다는 것을 알 때마다 IMO를 사용해야합니다 (형식, 범위 또는 지원되지 않을 수 있기 때문). 캐스트로 동일한 변환을 수행 할 수 있더라도 (다른 것을 사용할 수없는 경우). 누가 여러분의 코드를 읽을 것인지 명확하게 , 그리고 그것이 실패 할 수 있다는 것을 분명히합니다 (디버그 단순화).

캐스트를 사용해야하는 다른 모든 경우에는 선택의 여지가 없지만 다른 더 나은 방법을 사용할 수 있으면 사용하는 것이 좋습니다. 당신의 예에서의 변환 string에는 double가능한 한 (또한 당신이 그것을보다 효율적으로 제어를 얻을 수) 명시 적으로 많이 그것을해야하므로 매우 자주 사용 예를 들어, 실패합니다 (텍스트가 사용자로부터 온다 특히)하는 것이 뭔가 TryParse방법을.

편집 : 그들 사이의 차이점은 무엇입니까?

(대한 업데이트 된 질문에 따라 그리고 내가 전에 쓴 유지 하면 당신은 / 사용 할 수 있습니다 때에 비해 캐스트를 사용할 수 있습니다 Convert또한 (그들 사이의 차이가있는 경우입니다 명확히 다음 마지막 점) Convert용도 IConvertibleIFormattable인터페이스가 작업을 수행 할 수 있도록 캐스트와 함께 허용되지 않음).

짧은 대답은 그렇습니다. 그들은 다르게 행동합니다 . 나는 Convert클래스가 도우미 메서드 클래스처럼 보이지만 종종 약간의 이점 이나 약간 다른 동작을 제공합니다. 예를 들면 :

double real = 1.6;
int castedInteger = (int)real; // 1
int convertedInteger = Convert.ToInt32(real); // 2

꽤 다르죠? 캐스트는 잘리지 만 (우리 모두가 기대하는 것입니다) Convert가장 가까운 정수로 반올림을 수행합니다 (알지 못하는 경우 예상되지 않을 수 있음). 각 변환 방법에는 차이가 있으므로 일반적인 규칙을 적용 할 수 없으며 사례별로 확인해야합니다 … 19 가지 기본 유형을 다른 모든 유형으로 변환 할 수 있습니다 … 목록은 꽤 길 수 있습니다. MSDN 사례를 참조하는 것이 훨씬 좋습니다. 케이스!


답변

캐스팅은 컴파일러에게 “이 변수가 Bar라고 생각하는 것을 알고 있지만, 나는 당신보다 더 많이 알고 있습니다. 객체는 실제로 Foo입니다. 지금.” 그런 다음 런타임에 실제 객체가 실제로 Foo로 판명되면 코드가 작동하고 객체가 Foo가 아님이 밝혀지면 예외가 발생합니다. (특히 System.InvalidCastException.)

반면에 변환은 “Bar 유형의 객체를 주면 해당 Bar 객체에있는 것을 나타내는 새로운 Foo 객체를 만들 수 있습니다. 원래 객체를 변경하지 않을 것입니다.”라고 말하는 방법입니다. t 원래 객체를 다르게 취급하면 다른 가치에 기반한 새로운 무언가만들어 낼 수 있습니다.Convert.ToDouble 는 호출 끝날 것Double.Parse어떤 유형의 문자열이 어떤 숫자 값을 나타내는 지 결정하기위한 모든 종류의 복잡한 논리가 있습니다. 문자열을 다르게 double로 매핑하는 자체 변환 방법을 작성할 수 있습니다 (아마도 로마 숫자 등과 같은 숫자 표시에 대해 완전히 다른 규칙을 지원하기 위해). 변환은 무엇이든 할 수 있지만, 아이디어는 컴파일러에게 당신을 위해 아무것도하도록 요청하는 것이 아니라는 것입니다. 여러분의 도움없이 컴파일러는 a를 .NET에 매핑하는 방법을 알 수 없기 때문에 새 객체를 만드는 방법을 결정하는 코드를 작성 string하는 사람 double입니다.

그렇다면 언제 전환하고 언제 캐스팅합니까? 두 경우 모두 어떤 유형의 변수를 가지고 있고, A라고합시다. 그리고 우리는 B 유형의 변수를 원합니다. 우리의 A 객체가 실제로 실제로 B이면 우리는 캐스트합니다. 실제로 B가 아니라면이를 변환하고 프로그램이 A로부터 B를 얻는 방법을 정의해야합니다.


답변

에서 MSDN:

명시 적 변환 (캐스트) : 명시 적 변환에는 캐스트 연산자가 필요합니다. 변환에서 정보가 손실되거나 다른 이유로 변환이 성공하지 못할 캐스팅이 필요합니다 . 일반적인 예로는 정밀도가 낮거나 범위가 더 작은 형식으로의 숫자 변환과 기본 클래스 인스턴스를 파생 클래스로 변환하는 것이 있습니다.

다음 예를 고려하십시오.

double a = 2548.3;
int b;
b = (int)a; //2548 --> information (.3) lost in the conversion

그리고 또한:

캐스트는 변환을 수행 할 계획이며 데이터 손실이 발생할 수 있음을 알고 있음을 컴파일러에 명시 적으로 알리는 방법입니다.

호환되지 않는 유형 System.Convert간에 변환하려는 경우 클래스를 사용할 수 있습니다. 큰 차이점 사이 주조변환이 있다 컴파일런타임 . 유형 변환 예외는 런타임 에 나타납니다 . 즉, 런타임에 실패한 유형 캐스트 는를 throw합니다.
InvalidCastException


결론 : 캐스팅에서 당신은 컴파일러에게 a진짜 타입 b이고 만약 그렇다면 프로젝트는이 예제와 같이 오류없이 빌드 된다는 것을 말하고 있습니다 .

double s = 2;
int a = (int) s;

그러나 변환에서 당신은 컴파일러에게 a유형 의 새 객체를 만드는 방법이 있다고 말하고 있습니다. b제발 그것을하고 프로젝트는 오류없이 빌드하지만 런타임에 유형 캐스트가 실패하면InvalidCastException 말했듯 이 던져진다 .

예를 들어 아래 코드는 컴파일러가 유형의 표현식을 type DateTime으로 캐스팅 할 수 없음을 감지하므로 컴파일되지 않습니다 int.

DateTime s = DateTime.Now;
int a = (int)(s);

그러나 이것은 성공적으로 컴파일되었습니다.

DateTime s = DateTime.Now;
int a = Convert.ToInt32(s);

그러나 런타임에는 다음과 같은 내용이 표시됩니다 InvalidCastException.

‘DateTime’에서 ‘Int32’로의 캐스트가 잘못되었습니다.


답변

Convert.Double메서드는 실제로 내부적으로Double.Parse(string) 메서드를 .

어느 String유형이나 Double캐스팅은 항상 실패 때문에 유형은 두 가지 유형 사이의 명시 적 / 암시 적 변환을 정의합니다.

Double.Parse메서드는의 각 문자를 살펴보고의 문자 string값을 기반으로 숫자 값을 string만듭니다. 잘못된 문자가 있으면 Parse메서드가 실패합니다 ( Convert.Double메서드도 실패 함).


답변

귀하의 예에서 문자열을 double (비 정수 유형)으로 캐스트하려고 시도하고 있습니다.

작동하려면 명시 적 변환이 필요합니다.

그리고 나는 당신이 int로 변환 할 때 double 값의 소수 부분을 잃을 수 있기 때문에 Convert.ToDouble대신 사용할 수 있음을 지적해야합니다 Convert.ToInt64.

변수 값이 “5.25”인 경우 varDouble은 5.00 (Int64 로의 변환으로 인한 0.25 손실)이됩니다.

캐스팅과 변환에 대한 질문에 대답합니다.

캐스트 (명시 적 캐스트)가 명시 적 캐스트의 요구 사항을 충족하지 않습니다. 캐스트 연산자로 캐스트하려는 값이 유효하지 않습니다 (즉, 정수가 아님).

캐스팅 / 변환 규칙을 보려면 이 MSDN 페이지 를 방문하십시오.


답변

캐스팅에는 변환이 포함되지 않습니다. 즉, 값의 내부 표현이 변경되지 않습니다. 예:

object o = "Hello"; // o is typed as object and contains a string.
string s = (string)o; // This works only if o really contains a string or null.

당신은 변환 할 수 있습니다 doublestring 이 좋아

double d = 5;
string s = d.ToString(); // -> "5"

// Or by specifying a format
string formatted = d.ToString("N2"); // -> "5.00"

a string를 a 로 변환 할 수 있습니다 .double여러 가지 방법으로 (여기서는 두 가지 방법).

string s = "5";
double d = Double.Parse(s); // Throws an exception if s does not contain a valid number

또는 안전한 방법

string s = "5";
double d;
if (Double.TryParse(s, out d)) {
    Console.WriteLine("OK. Result = {0}", d);
} else {
    Console.WriteLine("oops!");
}


답변

string variable = "5.00";
double varDouble = (double)variable;

위의 변환은 단순히 언어에 의해 허용되지 않습니다. 다음은 숫자 유형에 대한 명시 적 캐스트 목록입니다. http://msdn.microsoft.com/en-us/library/yht2cx7b.aspx 보시다시피 모든 숫자 유형이 다른 숫자 유형으로 변환 될 수있는 것은 아닙니다.

여기에서 전송에 대한 추가 정보

그리고 이것이 Convert.ToDouble ()과 어떻게 다른가요?

유형을 캐스트 할 때 데이터 구조는 변경되지 않습니다. 음, 숫자 값 변환의 경우 몇 비트를 풀거나 추가 0 비트를 얻을 수 있습니다. 그러나 당신은 여전히 ​​숫자로 작업하고 있습니다. 당신은 그 숫자가 차지하는 메모리 양을 변경하고 있습니다. 컴파일러가 필요한 모든 작업을 수행하기에 충분히 안전합니다.

그러나 문자열을 숫자로 캐스트하려고 할 때 변수가 차지하는 메모리 양을 변경하는 것만으로는 충분하지 않기 때문에 그렇게 할 수 없습니다. 예를 들어 5.00문자열은 “숫자”의 시퀀스입니다. 53 (5) 46 (.) 48 (0) 48 (0)-ASCII 용이지만 문자열에는 비슷한 내용이 포함됩니다. 컴파일러가 문자열에서 처음 N (더블의 경우 4? 확실하지 않음) 바이트를 가져 오면 해당 조각에는 완전히 다른 이중 숫자가 포함됩니다. 동시에 Convert.ToDouble ()은 문자열의 각 기호를 사용하는 특수 알고리즘을 실행하고, 문자열이 숫자를 나타내는 경우 나타내는 숫자를 파악하고 두 배로 만듭니다. PHP와 같은 언어는 대략적으로 말하면 백그라운드에서 Convert.ToDouble을 호출합니다. 그러나 C #은 정적으로 형식화 된 언어처럼이를 수행하지 않습니다. 이를 통해 모든 작업이 형식에 안전하고 다음과 같은 작업을 수행하는 동안 예기치 않은 작업이 발생하지 않도록 할 수 있습니다.

double d = (double)"zzzz"