문제
현재이 코드에 새로운 확장 클래스를 추가하고 있습니다.
foreach (BaseType b in CollectionOfExtendedTypes) {
if (b is ExtendedType1) {
((ExtendedType1) b).foo = this;
}
else if (b is ExtendedType2) {
((ExtenedType2) b).foo = this;
}
else {
b.foo = this;
}
}
그리고 사용 방법이 있는지 궁금했습니다. is
스위치 문의 키워드 기능?
해결책
이것은 정말 좋은 다형성 구현의 상황처럼 보입니다. 파생 클래스에서 적절한 방법을 무시하면 루프에서 확인이 필요하지 않을 수 있습니다.
다른 팁
C# (7)의 최신 버전에는 이제이 기능이 포함됩니다.
유형 패턴은 간결한 유형 평가 및 변환을 가능하게합니다. 패턴 일치를 수행하기 위해 Switch 문과 함께 사용되면 표현식을 지정된 유형으로 변환 할 수 있는지 여부를 테스트하고 가능하다면 해당 유형의 변수로 캐스트합니다. 구문은 다음과 같습니다.
case type varname
아니요. 보다
C#에서는 "IS"키워드를 스위치 문의 일부로 사용할 수 없습니다. 스위치의 모든 케이스 레이블은 일정한 표현식으로 평가해야합니다. "is"는 일정한 표현으로 전환 할 수 없습니다.
유형을 켜는 데있어 고통을 확실히 느낍니다. 당신이 설명한 해결책은 실제로 작동하지만 x do y에 대해 말하는 방법입니다. b. 다음과 같이 글을 쓰는 것이 훨씬 더 나일 것입니다.
TypeSwitch.Do(
sender,
TypeSwitch.Case<Button>(() => textBox1.Text = "Hit a Button"),
TypeSwitch.Case<CheckBox>(x => textBox1.Text = "Checkbox is " + x.Checked),
TypeSwitch.Default(() => textBox1.Text = "Not sure what is hovered over"));
다음은이 기능을 달성하는 방법에 대해 쓴 블로그 게시물입니다.
http://blogs.msdn.com/jaredpar/archive/2008/05/16/switching-on-types.aspx
확인 유형에 Switch 문을 사용할 수는 없지만 문제를보다 관리하기 쉬운 코드베이스로 줄이는 것은 불가능하지 않습니다.
특정 상황과 요구 사항에 따라 고려할 것입니다.
사용 a
IDictionary<Type, T>
결과를 사전에 저장합니다. t 자체는 당신이 전화 할 수있는 대의원 일 수 있습니다. 상속에 대해 걱정할 필요가 없다면 작동합니다. 상속을위한 케이터링에는 조금 더 많은 작업이 필요합니다.스위치 문 내에서 클래스의 유형 이름 (문자열)을 사용합니다. 이것은 사용합니다
switch (b.GetType().Name)
그리고 깊은 상속 구조에 대한 옵션은 없습니다.
에 언급했듯이 대답 ~에서 미킷, 당신은 사용할 수 있습니다 패턴 수학 C# 7이 필요합니다.
코드의 예는 다음과 같습니다.
foreach (BaseType b in CollectionOfExtendedTypes) {
switch (b) {
case ExtendedType1 et1:
// Do stuff with et1.
et1.DoStuff();
break;
case ExtendedType2 et2:
// Do stuff with et2.
et2.DoOtherStuff();
break;
default:
// Do something else...
break;
}
}
메소드를 추가 할 수 있습니다 getType()
에게 BaseType
이는 각 콘크리트 서브 클래스에서 구현하여 고유 한 적분 ID (열거)를 반환하고이를 켜십시오.
실제로 스위치는 변수 (String 또는 int (또는 Enum))과 일치하여 Switch 문으로 일정한 표현식과 일치합니다.
http://msdn.microsoft.com/en-us/library/06tc147t(vs.71).aspx
C#에서는 스위치 문이 정수 및 문자열과 만 작동한다고 생각합니다.
유형의 케이스와 객체 지향 코드는 내 경험에 따라 그와 잘 어울리지 않는 것 같습니다. 이 상황에서 내가 선호하는 접근법은 다음과 같습니다 이중 디스패치 패턴. 요컨대 :
- 리스너 유형을 만듭니다 각 확장 된 유형에 대해 빈 가상 메소드 프로세스 (ExtendedTypen Arg)를 사용하면 배출됩니다.
- 가상 메소드를 추가하십시오 청취자를 인수로 취하는 기본 유형으로 디스패치 (리스너 리스너)를 디스패치하십시오. 구현은 Listener.process ((기본) this)를 호출하는 것입니다.
- 위에타다 적절한 것을 호출하기 위해 각 확장 유형의 디스패치 방법 ~ 위에짐 청취자 유형의 프로세스.
- 리스너 유형을 확장합니다 관심있는 각 하위 유형에 대한 적절한 프로세스 방법을 재정의함으로써.
인수 셔플 링 댄스는 파견 호출로 접어 좁아진 캐스트를 제거합니다. 수신기는 정확한 유형을 알고 있으며 그 유형의 정확한 과부하를 다시 호출하여 통신합니다. 이는 또한 .NET Compact 프레임 워크와 같은 구현에서 큰 성능을 얻는 것입니다. 여기서 좁은 캐스트는 매우 느리지 만 가상 파견이 빠릅니다.
결과는 다음과 같습니다.
public class Listener
{
public virtual void Process(Base obj) { }
public virtual void Process(Derived obj) { }
public virtual void Process(OtherDerived obj) { }
}
public class Base
{
public virtual void Dispatch(Listener l) { l.Process(this); }
}
public class Derived
{
public override void Dispatch(Listener l) { l.Process(this); }
}
public class OtherDerived
{
public override void Dispatch(Listener l) { l.Process(this); }
}
public class ExampleListener
{
public override void Process(Derived obj)
{
Console.WriteLine("I got a Derived");
}
public override void Process(OtherDerived obj)
{
Console.WriteLine("I got an OtherDerived");
}
public void ProcessCollection(IEnumerable collection)
{
foreach (Base obj in collection) obj.Dispatch(this);
}
}
컴파일러가 처리하는 방식 외에 다른 생각이 있습니다. switch
진술, 그리고 그것이 기능입니다 is
운영자. 다음 사이에는 큰 차이가 있습니다.
if (obj is Foo)
그리고
if (obj.GetType() == typeof(Foo))
이름에도 불구하고 is
운영자는 객체가 있는지 알려줍니다 호환 가능 주어진 유형의 경우 ~이다 주어진 유형의. 이것은 단호한 버그로 이어집니다 (이것은 분명하지만).
if (obj is System.Object)
{
//this will always execute
}
else if (obj is Foo)
{
//this will never execute
}
여기에서 많은 제안이 객체 유형을 사용하는 방향을 지적합니다. 당신이 정말로 원하는 것이 각 유형과 관련된 논리라면 괜찮습니다. 그러나 그런 경우라면, 사용할 때 조심스럽게 걷습니다. is
운영자.
또한 : 이러한 기본 유형을 수정할 수는 없지만 Owen의 제안을 사용할 수 없다는 의미는 아닙니다. 확장 방법을 구현할 수 있습니다.
public enum MyType { Foo, Bar, Baz };
public static class MyTypeExtension
{
public static MyType GetMyType(this Foo o)
{
return MyType.Foo;
}
public static MyType GetMyType(this Bar o)
{
return MyType.Bar;
}
public static MyType GetMyType(this Baz o)
{
return MyType.Baz;
}
}
그럼 당신 ~할 수 있다 a switch
성명:
switch (myObject.GetType())
{
case MyType.Foo:
// etc.