programing tip

유형 C #에서 케이스 전환

itbloger 2020. 12. 10. 19:08
반응형

유형 C #에서 케이스 전환


중복 가능성 :
C #- 'switch on type'보다 더 나은 대안이 있습니까?

안녕하세요, 클래스 유형에 대해 큰 if / else가 있다고 가정합니다. 스위치 케이스로 할 수있는 방법이 있습니까?

예 :

function test(object obj)
{
if(obj is WebControl)
{

}else if(obj is TextBox)
{

}
else if(obj is ComboBox)
{

}

등 ...

나는 다음과 같은 것을 만들고 싶다.

switch(obj)
{
case is TextBox:
break;
case is ComboBox:
break;

}

}


아니.

http://blogs.msdn.com/b/peterhal/archive/2005/07/05/435760.aspx

우리는 C # 언어에 대한 추가에 대한 많은 요청을 받고 있으며 오늘은 더 일반적인 것 중 하나 인 스위치 켜기 유형에 대해 이야기 할 것입니다. Switch on type은 매우 유용하고 직관적 인 기능처럼 보입니다. 값이 아닌 표현식의 유형을 전환하는 스위치와 같은 구조를 추가합니다. 다음과 같이 보일 수 있습니다.

switch typeof(e) { 
        case int:    ... break; 
        case string: ... break; 
        case double: ... break; 
        default:     ... break; 
}

이러한 종류의 문은 분리 된 유형 계층 구조 또는 소유하지 않은 유형을 포함하는 유형 계층 구조를 통한 디스패치와 같은 가상 메서드를 추가하는 데 매우 유용합니다. 이와 같은 예를 보면 해당 기능이 간단하고 유용하다고 쉽게 결론을 내릴 수 있습니다. "왜 # * & % $ 게으른 C # 언어 디자이너가 내 삶을 더 쉽게 만들고이 간단하고 시간을 절약 할 수있는 언어 기능을 추가하지 않겠습니까?"라고 생각할 수도 있습니다.

불행히도 많은 '간단한'언어 기능과 마찬가지로 유형 스위치는 처음 나타나는 것처럼 간단하지 않습니다. 문제는 다음과 같이 더 중요하고 덜 중요한 것을 볼 때 시작됩니다.

class C {}
interface I {}
class D : C, I {}

switch typeof(e) {
case C: … break;
case I: … break;
default: … break;
}

링크 : https://blogs.msdn.microsoft.com/peterhal/2005/07/05/many-questions-switch-on-type/

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

다음 코드는 실제 유형 (예 :에서 반환 된 것 GetType()) 만 보는 유형 스위치를 예상하는 것처럼 다소 작동합니다 .

public static void TestTypeSwitch()
{
    var ts = new TypeSwitch()
        .Case((int x) => Console.WriteLine("int"))
        .Case((bool x) => Console.WriteLine("bool"))
        .Case((string x) => Console.WriteLine("string"));

    ts.Switch(42);     
    ts.Switch(false);  
    ts.Switch("hello"); 
}

작동하는 데 필요한 기계가 있습니다.

public class TypeSwitch
{
    Dictionary<Type, Action<object>> matches = new Dictionary<Type, Action<object>>();
    public TypeSwitch Case<T>(Action<T> action) { matches.Add(typeof(T), (x) => action((T)x)); return this; } 
    public void Switch(object x) { matches[x.GetType()](x); }
}

예, 이름을 켤 수 있습니다 ...

switch (obj.GetType().Name)
{
    case "TextBox":...
}

다음은 유형을 전환 할 수 있도록 OP의 요구 사항에 맞출 수있는 사실로 유지되는 옵션입니다. 충분히 세게 가늘게 뜨면 실제 switch 문처럼 보입니다.

호출 코드는 다음과 같습니다.

var @switch = this.Switch(new []
{
    this.Case<WebControl>(x => { /* WebControl code here */ }),
    this.Case<TextBox>(x => { /* TextBox code here */ }),
    this.Case<ComboBox>(x => { /* ComboBox code here */ }),
});

@switch(obj);

x의 각 람다는 강력한 형식입니다. 캐스팅이 필요하지 않습니다.

이 마법이 작동하도록하려면 다음 두 가지 방법이 필요합니다.

private Action<object> Switch(params Func<object, Action>[] tests)
{
    return o =>
    {
        var @case = tests
            .Select(f => f(o))
            .FirstOrDefault(a => a != null);

        if (@case != null)
        {
            @case();
        }
    };
}

private Func<object, Action> Case<T>(Action<T> action)
{
    return o => o is T ? (Action)(() => action((T)o)) : (Action)null;
}

거의 눈물을 흘리 죠?

그럼에도 불구하고 작동합니다. 즐겨.


가장 간단한 방법은 역학을 사용하는 것입니다. 즉, Yuval Peled 답변과 같은 간단한 방법을 정의합니다.

void Test(WebControl c)
{
...
}

void Test(ComboBox c)
{
...
}

Then you cannot call directly Test(obj), because overload resolution is done at compile time. You have to assign your object to a dynamic and then call the Test method:

dynamic dynObj = obj;
Test(dynObj);

참고URL : https://stackoverflow.com/questions/7252186/switch-case-on-type-c-sharp

반응형