다운 캐스팅을 올바르게 사용하는 것은 무엇입니까?


67

다운 캐스팅은 기본 클래스 (또는 인터페이스)에서 서브 클래스 또는 리프 클래스로 캐스트하는 것을 의미합니다.

다운 캐스트의 예로는 System.Object다른 유형 으로 캐스트 할 수 있습니다 .

다운 캐스팅은 인기가없고 코드 냄새 일 수 있습니다. 객체 지향 교리는 예를 들어 다운 캐스팅 대신 가상 또는 추상 메서드를 정의하고 호출하는 것을 선호합니다.

  • 다운 캐스팅을위한 적절하고 적절한 사용 사례는 무엇입니까? 즉, 어떤 상황에서 다운 캐스트되는 코드를 작성하는 것이 적절합니까?
  • 답변이 "없음"인 경우 왜 언어에서 다운 캐스팅을 지원합니까?

5
설명하는 것을 보통 "다운 캐스팅"이라고합니다. 그 지식으로 무장하고, 먼저 자신의 연구를 더하고, 왜 발견 한 기존의 이유가 충분하지 않은지 설명 할 수 있습니까? TL; DR : 다운 캐스팅은 정적 타이핑을 중단하지만 때로는 유형 시스템이 너무 제한적입니다. 따라서 언어가 안전한 다운 캐스팅을 제공하는 것이 합리적입니다.
amon

다운 캐스팅을 의미합니까? 업 캐스팅은 슈퍼 클래스에서 서브 클래스로 다운 캐스팅과는 달리 클래스 계층 구조, 즉 서브 클래스에서 수퍼 클래스로 업스트림 될 것입니다.
Andrei Socaciu

내 사과 : 당신이 맞아요. "upcast"의 이름을 "downcast"로 변경하기 위해 질문을 편집했습니다.
ChrisW

@amon en.wikipedia.org/wiki/Downcasting 은 예제로 "문자열로 변환"을 제공합니다 (.Net은 virtual 사용을 지원합니다 ToString). Java는 C #에서 지원하는 제네릭을 지원하지 않기 때문에 다른 예제는 "Java 컨테이너"입니다. stackoverflow.com/questions/1524197/downcast-and-upcast 는 다운 캐스팅 무엇인지 알려 주지만 적절한 시기에 대한 예는 없습니다 .
ChrisW

4
@ChrisW before Java had support for generics아닙니다 because Java doesn't support generics. 그리고 amon은 당신에게 해답을 주었다. 당신이 작업하는 타입 시스템이 너무 제한적이고 그것을 바꿀 위치에 있지 않을 때.
Ordous

답변:


12

다운 캐스팅의 올바른 사용법은 다음과 같습니다.

그리고 나는 다운 캐스트 사용이 코드 냄새 라고 분명히 말하는 다른 사람들과 정중 하게 동의하지 않습니다.

Equals:

class A
{
    // Nothing here, but if you're a C++ programmer who dislikes object.Equals(object),
    // pretend it's not there and we have abstract bool A.Equals(A) instead.
}
class B : A
{
    private int x;
    public override bool Equals(object other)
    {
        var casted = other as B;  // cautious downcast (dynamic_cast in C++)
        return casted != null && this.x == casted.x;
    }
}

Clone:

class A : ICloneable
{
    // Again, if you dislike ICloneable, that's not the point.
    // Just ignore that and pretend this method returns type A instead of object.
    public virtual object Clone()
    {
        return this.MemberwiseClone();  // some sane default behavior, whatever
    }
}
class B : A
{
    private int[] x;
    public override object Clone()
    {
        var copy = (B)base.Clone();  // known downcast (static_cast in C++)
        copy.x = (int[])this.x.Clone();  // oh hey, another downcast!!
        return copy;
    }
}

Stream.EndRead/Write:

class MyStream : Stream
{
    private class AsyncResult : IAsyncResult
    {
        // ...
    }
    public override int EndRead(IAsyncResult other)
    {
        return Blah((AsyncResult)other);  // another downcast (likely ~static_cast)
    }
}

이것이 코드 냄새라고 말하는 경우, 불편으로 인해 피할 수 있더라도 더 나은 솔루션을 제공해야합니다. 더 나은 솔루션이 존재한다고 생각하지 않습니다.


9
"코드 냄새"는 "이 디자인은 확실히 나쁘다 " 는 의미가 아니며 "이 디자인은 의심 스럽다 " 는 의미 입니다. 본질적으로 의심스러운 언어 기능이 있다는 것은 언어 작성자의 실용주의 문제입니다.
Caleth

5
@Caleth : 그리고 내 전체 점은 이러한 설계는 모든 시간을 올 것을, 그리고이없는 것을 아무것도 절대적으로 내가 보여 디자인에 대한 본질적으로 의심은, 따라서 주조 코드 냄새가 없습니다.
Mehrdad

4
@Caleth 동의하지 않습니다. 코드 냄새는 코드가 나쁘거나 최소한 개선 될 수 있음을 의미합니다.
Konrad Rudolph

6
@Mehrdad 귀하의 의견은 코드 냄새가 응용 프로그램 프로그래머의 잘못이라고 생각합니다. 왜? 모든 코드 냄새가 실제 문제이거나 해결책이 될 필요는 없습니다. Martin Fowler에 따르면 코드 냄새는 단순히 "일반적으로 시스템의 더 깊은 문제에 해당하는 표면 표시"는 object.Equals해당 설명에 잘 맞습니다 (서브 클래스가 올바르게 구현할 수 있도록 수퍼 클래스에서 동등 계약을 올바르게 제공하려고합니다). 사소한). 응용 프로그램 프로그래머로서 우리는 그것을 해결할 수 없습니다 (경우에 따라 피할 수 있음)는 다른 주제입니다.
Voo

5
@Mehrdad 글쎄요. 원래 언어 디자이너 중 한 사람이 Equals.에 대해 어떻게 말하는지 봅시다. Object.Equals is horrid. Equality computation in C# is completely messed up(그의 답변에 대한 Eric의 의견). 언어 자체의 수석 디자이너 중 한 사람이 당신에게 틀렸다고 말할 때에도 당신의 의견을 재고하고 싶지 않은 것은 재밌습니다.
Voo

135

다운 캐스팅은 인기가없고 코드 냄새 일 수 있습니다.

동의하지 않습니다. 다운 캐스팅은 매우 인기가 있습니다 . 수많은 실제 프로그램에는 하나 이상의 다운 캐스트가 포함되어 있습니다. 코드 냄새 가 아닐 수도 있습니다. 그것은이다 확실히 코드 냄새. 그렇기 때문에 다운 캐스팅 작업을 프로그램의 텍스트에 명시해야합니다 . 냄새를보다 쉽게 ​​알아 차리고 코드 검토에주의를 기울일 수 있습니다.

어떤 상황에서 다운 캐스트되는 코드를 작성하는 것이 적절합니까?

다음과 같은 상황에서 :

  • 당신은 100 % 정확한 지식 표현의 컴파일 시간 형보다 명확한 표현의 실행시의 형태에 대한 사실을, 그리고
  • 컴파일 타임 유형에서 사용할 수없는 객체의 기능을 사용하려면 해당 사실을 활용해야합니다.
  • 처음 두 지점을 제거하기 위해 프로그램을 리팩토링하는 것보다 캐스트를 작성하는 데 시간과 노력을 더 잘 사용하는 것이 좋습니다.

컴파일러가 런타임 유형을 추론하거나보다 파생 된 유형의 기능이 필요하지 않도록 프로그램을 리팩토링 할 수 있도록 프로그램을 저렴하게 리팩토링 할 수있는 경우 그렇게하십시오. 다운 캐스트는 그 상황에 대한 언어에 추가 된 하드비용 때문에 프로그램을 리팩토링 할 수 있습니다.

왜 다운 캐스팅이 언어에 의해 지원됩니까?

C #은 할 일 이있는 실용 프로그래머를 위해 할 일이있는 실용 프로그래머가 발명했습니다 . C # 디자이너는 OO 순수 주의자가 아닙니다. 그리고 C # 형식 시스템은 완벽하지 않습니다. 설계 상 변수의 런타임 유형에 적용 할 수있는 제한 사항을 과소 평가합니다.

또한 다운 캐스팅은 C #에서 매우 안전합니다. 우리는 다운 캐스트가 런타임에 검증 될 것이라는 강력한 보증을 가지고 있으며, 검증 할 수 없으면 프로그램이 옳은 일을하고 충돌합니다. 이것은 훌륭합니다. 즉 형식 의미에 대한 100 % 올바른 이해가 99.99 % 올바른 것으로 판명되면 프로그램이 99.99 %의 시간 동안 작동하고 예상치 못한 동작 및 사용자 데이터의 0.01 % 손상 대신 나머지 시간과 충돌 함을 의미합니다. .


연습 : 명시적인 캐스트 연산자를 사용 하지 않고 C #에서 다운 캐스트를 생성하는 방법이 최소한 하나 있습니다. 그러한 시나리오를 생각할 수 있습니까? 이것들은 잠재적 인 코드 냄새이기 때문에 코드에서 매니페스트 캐스트없이 다운 캐스트 충돌을 일으킬 수있는 기능의 디자인에 어떤 디자인 요소가 있다고 생각합니까?


101
벽에있는 고등학교의 포스터를 기억하십시오. "인기있는 것이 항상 옳은 것은 아니며, 옳은 것이 항상 인기있는 것은 아닌가?" 당신은 그들이 약을 먹거나 고등학교에서 임신하지 못하게하려고 생각했지만 실제로 기술 부채의 위험에 대해 경고하고있었습니다.
corsiKa

14
물론 foreach 문인 @EricLippert. 이것은 IEnumerable이 일반적이기 전에 이루어졌습니다.
Arturo Torres Sánchez

18
이 설명은 나의 하루를 만들었다. 선생님으로서 C #이 왜 이런 식으로 설계되는지 자주 묻는 질문에 답을 얻습니다. 제 답변은 종종 귀하와 동료가 여기 및 블로그에서 공유 한 동기에 기초합니다. 후속 질문 "하지만 whyyyyy?! "에 대답하기가 종종 더 어렵습니다 . 그리고 여기에 완벽한 후속 답변이 있습니다. "C #은 할 일이있는 실용 프로그래머, 할 일이있는 실용 프로그래머가 발명했습니다.". :-) 감사합니다 @EricLippert!
Zano

12
제쳐두고 : 분명히 위의 의견에서 나는 우리가 A에서 B 로 다운 캐스트 를 받았다고 말하려고했습니다 . 클래스 계층 구조를 탐색 할 때 "위"와 "아래"와 "부모"와 "자식"의 사용을 정말로 싫어합니다. 내 글에서 항상 틀렸다. 유형 간의 관계는 수퍼 세트 / 서브 세트 관계이므로 해당 방향과 관련하여 위 또는 아래로 방향이 있어야하는 이유는 모르겠습니다. 그리고 "부모"로 시작하지 마십시오. 기린의 부모는 포유류가 아니며, 기린의 부모는 기린 씨와 부인입니다.
Eric Lippert

9
Object.Equals이다 무서운 . C #의 평등 계산은 완전히 엉망이되어 주석에서 설명하기에는 너무 엉망입니다. 평등을 나타내는 많은 방법이 있습니다. 그것들을 일관성이 없게 만드는 것은 매우 쉽다; 그것은 사실, 아주 쉽게 필요한 동등 연산자 (대칭, 재귀 및 이행 성)에 요구되는 특성을 위반하는. 오늘 처음부터 타입 시스템을 설계하고 있었는데 전혀 Equals(또는 GetHashcode또는 ToString) 없을 것 Object입니다.
Eric Lippert

33

이벤트 핸들러에는 일반적으로 서명이 MethodName(object sender, EventArgs e)있습니다. 어떤 경우에는 유형에 관계없이 sender또는 전혀 사용 하지 않고 이벤트를 처리 할 수 sender있지만 다른 sender경우에는 이벤트를 처리하기 위해 더 구체적인 유형으로 캐스트해야합니다.

예를 들어, 두 TextBox개의을 가질 수 있고 단일 델리게이트를 사용하여 각각의 이벤트를 처리하려고합니다. 그럼 당신은 캐스팅해야 senderA와 TextBox사용자가 이벤트를 처리하는 데 필요한 속성에 액세스 할 수 있도록 :

private void TextBox_TextChanged(object sender, EventArgs e)
{
   TextBox box = (TextBox)sender;
   box.BackColor = string.IsNullOrEmpty(box.Text) ? Color.Red : Color.White;
}

예,이 예에서는 TextBox내부적 으로 수행 한 자체 하위 클래스를 만들 수 있습니다 . 그러나 항상 실용적이거나 가능한 것은 아닙니다.


2
감사합니다. 좋은 예입니다. 이 TextChanged이벤트는 다음의 멤버입니다. Controlsender타입이 Control아닌 타입이 아닌지 궁금 합니다 object. 또한 (이론적으로) 프레임 워크가 각 서브 클래스에 대한 이벤트를 재정의 할 수 있었는지 궁금합니다 (예 : 발신자 유형으로 TextBox사용하여 새로운 버전의 이벤트를 가질 수 있음 TextBox) ... 로 TextBox)을 내부에 TextBox구현 () 새로운 이벤트 유형을 구현하지만, 응용 프로그램 코드의 이벤트 핸들러에서 내리 뜬을 필요로하지 않도록한다.
ChrisW

3
모든 이벤트에 고유 한 메소드 서명이있는 경우 이벤트 처리를 일반화하기 어렵 기 때문에 이는 허용 가능한 것으로 간주됩니다. 비록 대안이 실제로 더 번거롭기 때문에 모범 사례로 간주되는 것이 아니라 허용되는 제한이라고 생각합니다. 코드를 지나치게 복잡하게 만들지 않고 시작하는 TextBox sender것이 가능하다면 object sender그렇게 될 것이라고 확신합니다.
Neil

6
@Neil 이벤트 시스템은 임의의 데이터 청크를 임의의 객체로 전달할 수 있도록 특별히 만들어졌습니다. 유형 정확성에 대한 런타임 검사 없이는 불가능합니다.
Joker_vD

@Joker_vD 이상적으로는 API는 일반적인 반차를 사용하여 강력한 형식의 콜백 서명을 지원합니다. .NET이 (압도적으로) 그렇게하지 않는다는 사실은 단지 일반과 공분산이 나중에 소개 되었기 때문입니다. 다시 말해, 언어 / API의 부족으로 인해 여기서 (그리고 일반적으로 다른 곳에서) 다운 캐스트는 근본적으로 좋은 아이디어가 아니기 때문에 필요합니다.
Konrad Rudolph

@KonradRudolph 물론, 임의의 유형의 이벤트를 이벤트 큐에 어떻게 저장 하시겠습니까? 대기열을 없애고 직접 파견을 하시겠습니까?
Joker_vD

17

무언가 가 당신에게 슈퍼 타입을 줄 때 다운 캐스팅 이 필요하고 서브 타입에 따라 다르게 처리해야합니다.

decimal value;
Donation d = user.getDonation();
if (d is CashDonation) {
     value = ((CashDonation)d).getValue();
}
if (d is ItemDonation) {
     value = itemValueEstimator.estimateValueOf(((ItemDonation)d).getItem());
}
System.out.println("Thank you for your generous donation of $" + value);

아뇨, 좋은 냄새가 나지 않습니다. 완벽한 세계 Donation에는 추상적 인 방법이 getValue있으며 각 구현 하위 유형에는 적절한 구현이 있습니다.

그러나 이러한 클래스가 라이브러리에서 온 경우 변경할 수 없거나 변경하고 싶지 않은 것은 무엇입니까? 그런 다음 다른 옵션이 없습니다.


방문자 패턴을 사용하기에 좋은시기 인 것 같습니다. 또는 dynamic동일한 결과를 얻는 키워드입니다.
user2023861

3
아니 내가 생각 user2023861 @ 방문자 패턴이 기부 서브 클래스에서의 협력에 따라 달라집니다 - 즉, 기부는 추상적 인 선언 할 필요가 없다 void accept(IDonationVisitor visitor)그것의 서브 클래스의 특정 (예를 들어 오버로드) 메서드를 호출하여 구현하는을 IDonationVisitor.
ChrisW

@ChrisW, 당신이 맞습니다. 협력하지 않아도 dynamic키워드를 사용하여 계속 할 수 있습니다 .
user2023861

이 특별한 경우에 당신은 donationValue 메소드를 기부에 추가 할 수 있습니다.
user253751

@ user2023861 : dynamic여전히 다운 캐스팅 중입니다.
Mehrdad

12

댓글을 달 수 없기 때문에 Eric Lippert의 답변에 추가하려면 ...

제네릭을 사용하도록 API를 리팩토링하여 다운 캐스팅을 피할 수 있습니다. 그러나 제네릭은 2.0 버전까지 언어에 추가되지 않았습니다 . 따라서 자신의 코드에서 고대 언어 버전을 지원할 필요가 없더라도 매개 변수화되지 않은 레거시 클래스를 사용하고있을 수 있습니다. 예를 들어, 어떤 클래스는 type의 페이로드를 전달하도록 정의 될 수 있습니다.이 페이로드는 Object실제로 알고있는 유형으로 캐스트되어야합니다.


실제로 Java 또는 C #의 제네릭은 본질적으로 요소를 다시 사용하기 전에 수퍼 클래스 객체를 저장하고 올바른 (컴파일러 확인) 서브 클래스로 다운 캐스팅하는 안전한 래퍼라고 말할 수 있습니다. (항상 이렇게 서브 클래스 자체를 사용하는 코드를 다시 작성 C ++ 템플릿과는 달리 풀이 죽은 것을 피하기 - 자주하면 컴파일 시간과 실행 파일 크기의 비용으로, 메모리 성능을 높일 수있다.)
leftaroundabout

4

정적 언어와 동적 형식 언어 사이에는 상충 관계가 있습니다. 정적 타이핑은 컴파일러에게 (일부) 프로그램의 안전성에 대한 강력한 보장을 할 수있는 많은 정보를 제공합니다. 그러나 비용이 많이 들지만, 프로그램이 올바른지 알아야 할뿐만 아니라 컴파일러에게 이것이 사실임을 확신시키기 위해 적절한 코드를 작성해야합니다. 다시 말해 주장을하는 것보다 주장을하는 것이 더 쉽습니다.

컴파일러에 대해 입증되지 않은 주장을 하는 데 도움이되는 "안전하지 않은"구조가 있습니다 . 예를 들어, 무조건 Nullable.Value다운 캐스트, dynamic객체 등에 대한 무조건 호출 a은 이를 증명할 필요 없이 클레임을 주장 할 수있게합니다 ( " String나는 내가 틀렸다면 객체를이라고 주장합니다 InvalidCastException") . 이는 증명하는 것이 가치있는 것보다 훨씬 어려운 경우에 유용 할 수 있습니다.

이를 악용하는 것은 위험하므로 명시 적 다운 캐스트 표기법이 존재하고 필수입니다. 안전하지 않은 작업에주의를 기울이는 의미 의 구문 소금 입니다. 이 언어 암시 적 다운 캐스팅 (유추 된 유형이 모호하지 않은)으로 구현되었을 있지만이 안전하지 않은 작업은 숨겨져 바람직하지 않습니다.


그렇다면 이런 종류의 "검증되지 않은 주장"을 만드는 것이 필요하거나 바람직한 곳 (예 : 좋은 관행)에 대한 몇 가지 예를 들어 본 것 같습니다.
ChrisW

1
리플렉션 작업의 결과를 캐스팅하는 것은 어떻습니까? stackoverflow.com/a/3255716/3141234
Alexander

3

다운 캐스팅은 몇 가지 이유로 나쁜 것으로 간주됩니다. 안티 -OOP이기 때문에 주로 생각합니다.

다형성이 당신이 갈 필요가 없다는 것을 의미하기 때문에 OOP는 당신이 다운 캐스팅 할 필요가 없다면 정말로 그것을 원할 것입니다

if(object is X)
{
    //do the thing we do with X's
}
else
{
    //of the thing we do with Y's
}

당신은 단지

x.DoThing()

코드는 자동적으로 옳은 일을합니다.

다운 캐스트하지 말아야 할 몇 가지 '딱딱한'이유가 있습니다.

  • C ++에서는 느립니다.
  • 잘못된 유형을 선택하면 런타임 오류가 발생합니다.

그러나 일부 시나리오에서 다운 캐스팅에 대한 대안은 추악 할 수 있습니다.

전형적인 예는 메시지 처리입니다. 여기서 처리 기능을 오브젝트에 추가하지 않고 메시지 프로세서에 보관하십시오. 그런 다음 MessageBaseClass처리 할 배열에 톤이 있지만 올바른 처리를 위해서는 하위 유형별로 하나씩 필요합니다.

Double Dispatch를 사용하여 문제를 해결할 수 있습니다 ( https://en.wikipedia.org/wiki/Double_dispatch ) ...하지만 문제가 있습니다. 또는 이러한 어려운 이유로 위험에 처한 간단한 코드로 다운 캐스트 할 수도 있습니다.

그러나 이것은 제네릭이 발명되기 전이었습니다. 이제 나중에 세부 사항이 지정된 유형을 제공하여 다운 캐스팅을 피할 수 있습니다.

MessageProccesor<T> 지정된 유형별로 메소드 매개 변수 및 리턴 값을 변경할 수 있지만 여전히 일반 기능을 제공합니다.

물론 아무도 OOP 코드를 작성하도록 강요하지 않으며, 리플렉션과 같이 제공되었지만 찡그린 많은 언어 기능이 있습니다.


1
나는, C ++에서 특히 경우 느린 의심 static_cast대신에 dynamic_cast.
ChrisW

"메시지 처리"- lParam특정 의미로 캐스트 하는 것을 의미한다고 생각 합니다. 그래도 이것이 좋은 C # 예제인지 확실하지 않습니다.
ChrisW

3
@ChrisW-예, static_cast항상 빠릅니다 ...하지만 실수를하고 유형 이 예상 한 것이 아닌 경우 정의되지 않은 방식으로 실패하지 않을 것이라고 보장하지는 않습니다 .
Jules

@ 줄스 : 그것은 요점 옆에 있습니다.
Mehrdad

@Mehrdad, 정확히 요점입니다. C ++에서 동등한 C # 캐스트를 수행하는 것이 느립니다. 이것이 주조에 대한 전통적인 이유입니다. 대체 static_cast는 동일하지 않으며 정의되지 않은 동작으로 인해 더 나쁜 선택으로 간주됩니다
Ewan

0

앞에서 언급 한 모든 것 외에도 객체 유형 인 Tag 속성을 상상해보십시오. 나중에 원하는대로 사용할 수 있도록 선택한 객체를 다른 객체에 저장하는 방법을 제공합니다. 이 속성을 다운 캐스트해야합니다.

일반적으로 오늘까지 무언가를 사용하지 않는 것이 항상 쓸모없는 무언가를 나타내는 것은 아닙니다. ;-)


예를 들어 .net의 Tag 속성은 무엇입니까?를 참조하십시오 . 누군가가 쓴 답 중 하나 에서 Windows Forms 응용 프로그램의 사용자에게 지침을 입력하는 데 사용했습니다. 컨트롤 GotFocus 이벤트가 트리거되면 지침 Label.Text 속성에 지침 문자열이 포함 된 컨트롤 Tag 속성 값이 할당되었습니다. 속성 Control을 사용하는 대신 '확장'하는 다른 방법 은 각 컨트롤의 레이블을 저장할 위치 object Tag를 만드는 것 Dictionary<Control, string>입니다.
ChrisW

1
나는 Tag.Net 프레임 워크 클래스의 공용 속성 이기 때문에이 대답을 좋아합니다.이 클래스는 당신이 그것을 사용해야한다고 보여줍니다.
ChrisW

@ChrisW는 : 결론은 잘못 (또는 오른쪽) 대답하지만, 거기에 공공 .NET 기능이 많이 있기 때문에, 그 실수 추론의주의 입니다 오래된 (말은 System.Collections.ArrayList)하거나 (예를 들어, 사용되지 않는 IEnumerator.Reset).
Mehrdad

0

내 작품에서 다운 캐스팅을 가장 일반적으로 사용하는 것은 Liskov의 대체 원칙을 어기는 일부 바보 때문입니다.

타사 라이브러리에 인터페이스가 있다고 상상해보십시오.

public interface Foo
{
     void SayHello();
     void SayGoodbye();
 }

그리고 그것을 구현하는 2 개의 클래스. Bar그리고 Qux. Bar잘 동작합니다.

public class Bar
{
    void SayHello()
    {
        Console.WriteLine(“Bar says hello.”);
    }
    void SayGoodbye()
    {
         Console.WriteLine(“Bar says goodbye”);
    }
}

그러나 Qux잘 동작하지 않습니다.

public class Qux
{
    void SayHello()
    {
        Console.WriteLine(“Qux says hello.”);
    }
    void SayGoodbye()
    {
        throw new NotImplementedException();
    }
}

글쎄 ... 이제 선택의 여지가 없다. 나는 내 프로그램이 충돌 정지에 올 것을 방지하기 위해 체크와 (아마도) 풀이 죽은를 입력합니다.


1
이 특정 예에는 해당되지 않습니다. SayGoodbye를 호출 할 때 NotImplementedException을 잡을 수 있습니다.
당 폰 Zweigbergk

그것은이다 지나치게 어쩌면 간단한 예,하지만 기존의 닷넷의 일부 작품은 조금 API와이 상황에 실행하겠습니다. 때로는 코드를 작성하는 가장 쉬운 방법은 안전한 캐스팅 ala var qux = foo as Qux;입니다.
RubberDuck 2012

0

또 다른 실제 예는 WPF VisualTreeHelper입니다. 다운 캐스트를 사용 DependencyObject하여 Visual및 로 캐스트 합니다 Visual3D. 예를 들어 VisualTreeHelper.GetParent 입니다. 다운 캐스트는 VisualTreeUtils.AsVisualHelper 에서 발생합니다 .

private static bool AsVisualHelper(DependencyObject element, out Visual visual, out Visual3D visual3D)
{
    Visual elementAsVisual = element as Visual;

    if (elementAsVisual != null)
    {
        visual = elementAsVisual;
        visual3D = null;
        return true;
    }

    Visual3D elementAsVisual3D = element as Visual3D;

    if (elementAsVisual3D != null)
    {
        visual = null;
        visual3D = elementAsVisual3D;
        return true;
    }            

    visual = null;
    visual3D = null;
    return false;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.