문제

을 작성할 때 switch 문,가 나타납니다 두 가지 제한 사항이 무엇에 전환할 수 있습니다 경우에 문이 있습니다.

예를 들면 다음과 같습니다(예,내가 알고 있는 경우에,당신은 이런 일은 아마 그것이 의미하 객체지향 (EI)아키텍처는 불확실한-이것은 단지 예제!),

  Type t = typeof(int);

  switch (t) {

    case typeof(int):
      Console.WriteLine("int!");
      break;

    case typeof(string):
      Console.WriteLine("string!");
      break;

    default:
      Console.WriteLine("unknown!");
      break;
  }

여기에는 스위치()문을 실패하고'의 가치는 완전한 유형 예상되는'그리고 실패할 경우 문장과'일정한 값은 예상'.

왜 이러한 제한이 장소에서,그리고 무엇을 근본적인 정당성이 있는가?보이지 않는데는 이유 switch 에 굴복하는 정적 분석,그 이유를 전환하는 값에는 필수불가결한 요소가 되고 있(즉,원시).는 무엇입 정당성이 있는가?

도움이 되었습니까?

해결책

이것은 우리를 촉발,일부 논... 기 때문에 그것이 잘못입:

Switch 문이 동일하지 않습 것으로 큰 경우-다른 문입니다.각각의 경우 고유해야 합 및 평가 으로 합니다.Switch 문가 일정한 시점에 관계 없이 어떻게 많은 경우에 당신은 있습니다.는 경우-다른 사람 문 평가하여 각 조건 를 찾을 때까지 하는 것은 사실이다.


사실,C#switch 문 항상 일정한 시간 지점에 있습니다.

어떤 경우에는 컴파일러를 사용하 CIL switch 문는 실제로 일정한 시점을 사용하여 이동이다.그러나,스파의 경우 같은 지적해 Ivan Hamilton 컴파일러를 생성할 수 있습니다.

이것은 실제로 매우 쉽게 확인하여 작성하여 다양한 C#switch 문,일부 sparse,일부 조밀하고,결과 CIL 과 ildasm.exe 도구입니다.

다른 팁

그것은 혼동하지 않는 것이 중요 C#switch 문 CIL 스위치 명령입니다.

CIL 스위치 점프,테이블을 필요로 하는 인덱스의 집합으로 점프 주소입니다.

이것은 단지 유용한 경우 C#스위치의 경우 인접:

case 3: blah; break;
case 4: blah; break;
case 5: blah; break;

그러나 거의 사용하지 않는 경우:

case 10: blah; break;
case 200: blah; break;
case 3000: blah; break;

(당신은 테이블이 필요~3000 항목 크기 만 3 슬롯 사용)

비 초고속 무선 인터넷을 무료로 이용 표정,컴파일러를 시작할 수 있습을 수행하는 선형는 경우-다른 경우-다른 사람을 확인합니다.

와 큰 초고속 무선 인터넷을 무료로 이현정,컴파일러와 함께 시작할 수 있습 binary 트리 검색,그리고 마지막으로는 경우-다른 경우-다른 사람은 지난 몇 항목입니다.

식으로 세트를 포함하의 덩어리에 인접한 아이템,컴파일러는 바이너리 트리 검색,그리고 마지막으로 CIL 스위치입니다.

이것은 전체의"메이스"&"mights",그리고 그것은에 의존하는 컴파일러(다를 수 있습니다 모노와 함께 또는 회전자).

나는 복제에 대한 결과를 내을 사용하여 기계 인접한 경우:

총 시간을 실행하는 10 일 방법으로 스위치,10000 반복(ms):25.1383
대략적인 시간당 10 일 방법 스위치(ms):0.00251383

총 시간을 실행하는 방법 50 스위치,10000 반복(ms):26.593
대략적인 시간당 50 방법 스위치(ms):0.0026593

총 시간을 실행하 5000 방법으로 스위치,10000 반복(ms):23.7094
대략적인 시간별 5000 방법 스위치(ms):0.00237094

총 시간을 실행하 50000 방법으로 스위치,10000 반복(ms):20.0933
대략적인 시간별 50000 방법 스위치(ms):0.00200933

다음했을 사용하여 인접하지 않은 경우에는 표현식

총 시간을 실행하는 10 일 방법으로 스위치,10000 반복(ms):19.6189
대략적인 시간당 10 일 방법 스위치(ms):0.00196189

총 시간을 실행하는 500 방법으로 스위치,10000 반복(ms):19.1664
대략적인 시간당 500 방법 스위치(ms):0.00191664

총 시간을 실행하 5000 방법으로 스위치,10000 반복(ms):19.5871
대략적인 시간별 5000 방법 스위치(ms):0.00195871

비 초고속 무선 인터넷을 무료로 이용 50,000 케이스 스위치문이 컴파일되지 않습니다.
"는 표현은 너무 길거나 복잡한 컴파일 근처'ConsoleApplication1.프로그램입니다.Main(string[])'

재미있는 것은 여기에는 이진 나무는 검색 조금 나타납니다(아마는 통계적으로)보다 빨리 CIL 스위치 명령입니다.

브라이언,사용했던 단어"일정"는 매우 명확한 의미에서 전산 복잡도 이론의 관점이다.는 동안 단순한 인접한 정수로 들을 생산할 수 있습 CIL 는 것으로 간주됩 O(1)(일정),희소 예 O(로그 n)(로그),클러스터 예 거짓말이 어딘가에,그 사이에 작은 예 O(n)(linear).

이지 주소의 문자열 상황에서는 정적 Generic.Dictionary<string,int32> 할 수 있을 만들고 고통을 것입니다 확실한 오버헤드를 처음 사용.성능 여기 있을 것입에 의존하의 성능 Generic.Dictionary.

는 경우에 당신은 확인 C#언어 Specification 지 않는(CIL spec) 당신이 찾을 수"15.7.2switch 문은"언급이 없는"일정한 시간에"나는 근본적인 구현을 사용한 CIL 스위치침(수 있는 아주주의의 가정은 일).

에서 하루의 끝,C#스위치에 대해 정수현에 현대적인 시스템은 마이크로초의 작업,그리고 일반적으로 가치에 대한 걱정.


물론 이러한 시대에 따라 달라집니다 기계 및 조건입니다.나지 않을 주의하여 이러한 타이밍이 시험,마이크로초의 기간을 우리가 얘기하는 의해 작게 어떤"진짜"코드를 실행하(고 포함해야 합니다 일부는"실제 코드는"그렇지 않으면 컴파일러 최적화점다),또는에서 지터 시스템입니다.나의 답변에 따라 사용 IL DASM 검사 CIL 에 의해 만들어는 C#컴파일러입니다.물론,이것이 최종적으로 실제 지침을 CPU 를 실행하는 그에 의해 만들어 JIT.

체크인 최종 CPU 지침은 실제로 실행에 내 x86 기계 및 확인할 수 있습니다 간단한 인접한 세트 스위치가 다음과 같은 작업을 수행:

  jmp     ds:300025F0[eax*4]

어디 바이너리 트리를 검색이 가득:

  cmp     ebx, 79Eh
  jg      3000352B
  cmp     ebx, 654h
  jg      300032BB
  …
  cmp     ebx, 0F82h
  jz      30005EEE

첫 번째 이유는 마음에 오 역사:

대부분의 C,C++및 Java 프로그래머 익숙하지 않은 이러한 자유,그들이 요구하지 않습니다.

다른,더 많은 유효한 이유는 언어 복잡성을 증가시킬 것입:

첫째,한체와 비교할 .Equals()== operator?모두가 유효한 경우가 있습니다.우리는 새로운 소개 구문을 하면 이렇게 할 수 있습니까?우리는 프로그래머 소개하는 자신의 비교 방법?

또한할 수 있도록,전환하는 개체에 대한 것입 휴식의 기본에 대해 가정 switch.두 가지에 관한 규칙 switch 문는 컴파일러를 할 수 없을 것입을 적용하는 경우 객체를 허용하는 스위치(보 C#version3.0 언어 specification, §8.7.2):

  • 의 값 스위치 라벨 일정
  • 의 값 스위치 라벨 (그래서 그만 한 스위치 블록 선택할 수 있어 스위치-expression)

이 코드를 들어에서 가정의 경우는 일정하지 않는 경우 값을 허용되었다:

void DoIt()
{
    String foo = "bar";
    Switch(foo, foo);
}

void Switch(String val1, String val2)
{
    switch ("bar")
    {
        // The compiler will not know that val1 and val2 are not distinct
        case val1:
            // Is this case block selected?
            break;
        case val2:
            // Or this one?
            break;
        case "bar":
            // Or perhaps this one?
            break;
    }
}

무엇을 할 것 코드가?어떤 경우 문을 순서를 바꾸?실제로,이유 중 하나 C#만든 스위치 가을 통해 불법은 switch 문 될 수 있는 임의로 재배열.

이러한 규칙에 위치한 이유-도록 프로그래머 수 있습을 보면서 하나의 경우 블록을 알고,특정 정확한 상태에서는 차단을 입력합니다.상기 스위치 문의 성장으로 100 선이나 이상(고),이러한 지식은 매우 중요한 것입니다.

By the way,VB,같은 기본적인 아키텍처,할 수 있습이 훨씬 더 유연한 Select Case 진술(위의 코드 작업에 VB)고 아직도 생산 효율적인 코드는 이것이 가능한 그래서 인수하여 techical 제약은 신중하게 고려되어야한다.

주로 해당 제한 사항이 있는 장소에서 때문에 언어 디자이너가 있습니다.기본 정당화 될 수 있습 호환성을 더 빨리 습득할 수 있는 역사상,또는 단순화의 컴파일러 디자인이다.

컴파일러(가)선택:

  • 들이 있는 경우-다른 문의
  • 사용 MSIL 스위치침(뛰어 테이블)
  • 를 구축 일반적입니다.사전<string,int32>채 그것은 처음에 사용,전화 일반적입니다.사전<>::TryGetValue() 에 대한 지수로 전달하는 스위치 MSIL 침(뛰어 테이블)
  • 용 조합의 경우 else's&MSIL "스위치"점프

Switch 문의하지 않은 일정한 시간 지점에 있습니다.컴파일러에서 찾을 수 있습니다 짧은 상처를 사용하여(해시 buckets,etc.),하지만 더 복잡한 경우를 생성할 것이 더 복잡한 MSIL 코드와 함께 일부 경우 분기 이전에 다른 사람보다.

을 처리하는 문자열을 경우 컴파일러는 끝날 것입니다(어떤 점에서)을 이용하여.Equals(b)(그리고 아마도.GetHashCode()).내가 될 것이라고 생각 trival 를 위한 컴파일러를 사용하여 어떤 객체를 만족하는 이러한 제약 조건이 있습니다.

으로 필요한 정전 경우 식...일부 사람들의 최적화(해시,캐싱,등)에 사용할 수 없는 경우에는 식지 않았다 결정적입니다.그러나 우리가 보았을 것이 때로는 컴파일러에서 선택한 단순한 경우-다른 경우-다른 사람도 어쨌든...

편집: lomaxx -의 이해"typeof"연산자입니다 올바르지 않습니다.는"typeof"연산자를 사용하여 얻 시스템입니다.유체 유형(아무것도 수퍼 또는 인터페이스).검사 실행간의 호환성을 객체에 지정된 형식"is"연산자의 일이 아니다.의 사용"typeof"여기를 표현하는 객체 관계가 없습니다.

는 동안에는 주제에 따라,제프우드, switch 문 프로그래밍 극악.용을 절약해줍니다.

할 수 있습 같은 작업을 수행합을 사용하여 테이블이 있습니다.예를 들어:

var table = new Dictionary<Type, string>()
{
   { typeof(int), "it's an int!" }
   { typeof(string), "it's a string!" }
};

Type someType = typeof(int);
Console.WriteLine(table[someType]);

보이지 않는데는 이유 switch 문을 succomb 을 정적 분석만

사실,그것은 없 하고,많은 언어를 실제로 사용하여 동적인 스위치의 문이 있습니다.이미 그러나 그 방법"의 경우"절을 변경할 수 있는 행동의 코드입니다.

거기에 몇 가지 흥미로운 정보 뒤에 디자인이 결정을 내는 들어가서"스위치"에 여기: 왜 C#switch 문계를 허용하지 않을을 통하여,하지만 여전히 필요하신가요?

수 동적인 케이스 표정을 지도할 수 있는 괴물과 같은 이 PHP 코드:

switch (true) {
    case a == 5:
        ...
        break;
    case b == 10:
        ...
        break;
}

는 솔직해야 사용 if-else 문입니다.

Microsoft 마지막으로 당신을 들었습니다!

지금 C#7 할 수 있습니다:

switch(shape)
{
case Circle c:
    WriteLine($"circle with radius {c.Radius}");
    break;
case Rectangle s when (s.Length == s.Height):
    WriteLine($"{s.Length} x {s.Height} square");
    break;
case Rectangle r:
    WriteLine($"{r.Length} x {r.Height} rectangle");
    break;
default:
    WriteLine("<unknown shape>");
    break;
case null:
    throw new ArgumentNullException(nameof(shape));
}

이것은 이유지만,C#사양 섹션 8.7.2 다음 상태:

통치형 스위치의 문에 의해 설립 된 스위치 표현이다.는 경우 유형 스위치의 표현입니다 sbyte,바이트 단,ushort,int,uint,long,ulong,문자,문자열,또는 enum-입력,다음 통치형 스위치의 문입니다.그렇지 않으면,정확히 한 개의 사용자 정의 implicit conversion(§6.4)존재해야에서의 유형은 스위치를 표현하면 다음 중 하나 가능한 통치 유형:sbyte,바이트 단,ushort,int,uint,long,ulong,문자,문자열입니다.지 않는 경우 이러한 암시적으로 변환이 존재하거나,하나 이상일 경우에는 이러한 암시적으로 변환이 존재하는 컴파일시 오류가 발생합니다.

C#3.0 양의 위치는 다음과 같습니다.http://download.microsoft.com/download/3/8/8/388e7205-bc10-4226-b2a8-75351c669b09/CSharp%20Language%20Specification.doc

유다의 대답은 위의 아이디어를 얻었다.당신은 할 수 있습니다"가짜"OP 스위치 동작을 위하여 Dictionary<Type, Func<T>:

Dictionary<Type, Func<object, string,  string>> typeTable = new Dictionary<Type, Func<object, string, string>>();
typeTable.Add(typeof(int), (o, s) =>
                    {
                        return string.Format("{0}: {1}", s, o.ToString());
                    });

이것은 당신을 연결하는 동작으로 형식과 같은 스타일위치 문입니다.나는 그것을 믿는 혜택을 추가되는 키가 대신 스위치 스타일의 뛰어 테이블을 때 컴파일을 제공합니다.

나는 가정이 없는 근본적인 이유 컴파일러는 수 없이 자동으로 번역 switch 문으로:

if (t == typeof(int))
{
...
}
elseif (t == typeof(string))
{
...
}
...

지 않습니다 하지만 많은에 의해 얻는다.

Case 문에 필수적인 유형을 허용하는 컴파일러를 만들 수를 최적화:

  1. 이 없 복제(지 않는 한 당신이 중복되는 경우 상표,는 컴파일러는 검출).에서 당신의 예 t 와 일치할 수 있는 여러 종류 때문에 상속이 있습니다.해 첫 경기를 실행할?모?

  2. 컴파일러를 구현 하도록 선택할 수 있습니다 switch 문을 통해 중요한 유형으로 점프하는 테이블을 피하는 모든 비교할 수 있습니다.전환하는 경우 열거에 있는 정수 값은 0~100 그것은 배열을 만들 100 점에서 그것은,하나는 각 스위치에 대한 문의입니다.런타임에 그것은 단순히 보이는 주소에서 배열에 따라 정수 값으로 전환되고 있다.이것은 훨씬 더 나은 런타임 성능을 수행하는 것보다 100 을 비교할 수 있습니다.

에 따라 스위치 진술 문서 이 있는 경우 명확한 방법을 암시적으로 변환하여 객체를 필수적인 입력,그것이 허용됩니다.나는 당신이 기대하는 행위는 각각의 경우에 대해 문의 것으로 교체 if (t == typeof(int)), 하지만 열리는 전체할 수 있는 벌레를 얻을 때 과부는 연산자입니다.행동을 변경할 때 구현을 위한 세부사항 switch 문는 경우는 변경을 쓴 귀==무시게 되었습니다.을 줄여 비교를 통합 형식 문자열을 그 일을 줄일 수 있는 적분형(과하는 것)그들은 잠재적인 문제점을 피하십시오.

썼다:

"스위치 문은 일정한 시점에 관계없이 많은 경우에 당신은 있습니다."

이후 언어를 허용 문자열 에 사용되는 형식을 switch 문에서 나는 컴파일러를 생성할 수 없습에 대한 코드를 일정한 시간 지점 구현에 대한 이 유형과 요구를 생성하는 경우-다음 스타일입니다.

@mweerden-아 내가 참조하십시오.감사합니다.

지 않는 많은 경험을 가지고 있 C#다.순 있지만 그것은 언어 디자이너 허용하지 않는 정적에 액세스하는 유형을 시스템을 제외하고 좁은 상황이다.이 typeof 키워드 객체를 반환하는 이가에서 액세스할 수 있는 실행시간만 있습니다.

나는 생각 Henk 그것을 못을 박았으로"아니 sttatic 액세스 유형 시스템"일

또 다른 옵션은 없다는 것을 주문 형식으로 숫자 및 문자열이 될 수 있습니다.따라서 형식이 스는 것을 건설할 검색 트리에,그냥 선형 검색합니다.

동의 이 댓글 는 테이블을 사용하 중심의 접근 방식은 종종 더 나은 것이 됩니다.

C#1.0 이 가능하지 않았기 때문에 그것은 없 generics 및 익명습니다.새로운 버전의 C#는 비계 이 작업을 확인합니다.데 표기에 대한 개체 리터럴입니다 또한 도움이 됩니다.

내가 사실상 지식 C#지만,저는 하위 단순으로 촬영에서 발생하는 다른 언어에 대해 생각하지 않고 더 일반적 또는 개발자가 결정하는 연장 그 가치가 없습니다.

엄밀히 말하면 당신은 절대적으로 맞는 아무 이유도 없을 넣어 이러한 제한에습니다.하나는 의심되는 이유는 허용되는 경우 구현하는 것은 매우 효율적인(에 의해 제안으로는 브라이언하고 자신(44921))지만,의심의 구현은 매우 효율적인(w.r.t.는 경우-문장)내가 사용하는 경우 정수 및 일부를 임의 경우(예:345,-4574 및 1234203).그리고 어떤 경우에,무엇을 해칠 수 있도록 이에 대한 모든 것(적어도 이상)고 말하는 그것은 단지 효율에 대한 특정한 경우(이러한 대로(거의)연속 번호).

내가 할 수 있습니다,그러나 상상할 수 있을 제외하려는 형식이기 때문에 등의 이유로 하나에 의해 주어진 lomaxx(44918).

편집:@헹크(44970):는 경우 문자열을 극대로 공유하고,문자열과 동일한 콘텐츠가 포인터를 동 메모리 위치뿐만 아니라.그런 다음 경우에 있는지 확인할 수 있습니다 문자열에 사용되는 경우에 저장된 연속적으로 메모리에서,당신이 할 수있는 매우 효율적으로 구현하는 스위치(즉실행 순서는 2 비교하여,또한 그 두 점프).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top