鉴于c#不能切换类型(我收集到没有作为特殊情况添加,因为关系意味着可能应用多个不同的情况),有没有更好的方法来模拟类型切换?

void Foo(object o)
{
    if (o is A)
    {
        ((A)o).Hop();
    }
    else if (o is B)
    {
        ((B)o).Skip();
    }
    else
    {
        throw new ArgumentException("Unexpected type: " + o.GetType());
    }
}

当前回答

你应该重载你的方法,而不是尝试自己去消除歧义。到目前为止,大多数答案都没有考虑到未来的子类,这可能会导致以后真正可怕的维护问题。

其他回答

如果你知道你期待的类,但你仍然没有一个对象,你甚至可以这样做:

private string GetAcceptButtonText<T>() where T : BaseClass, new()
{
    switch (new T())
    {
        case BaseClassReview _: return "Review";
        case BaseClassValidate _: return "Validate";
        case BaseClassAcknowledge _: return "Acknowledge";
        default: return "Accept";
    }
}

创建一个超类(S),并使a和B从它继承。然后在S上声明一个每个子类都需要实现的抽象方法。

这样做,"foo"方法还可以将其签名更改为foo (S o),使其类型安全,并且不需要抛出那个丑陋的异常。

是的,感谢c# 7可以实现这一点。下面是如何做到的(使用表达式模式):

switch (o)
{
    case A a:
        a.Hop();
        break;
    case B b:
        b.Skip();
        break;
    case C _: 
        return new ArgumentException("Type C will be supported in the next version");
    default:
        return new ArgumentException("Unexpected type: " + o.GetType());
}

你可以创建重载方法:

void Foo(A a) 
{ 
    a.Hop(); 
}

void Foo(B b) 
{ 
    b.Skip(); 
}

void Foo(object o) 
{ 
    throw new ArgumentException("Unexpected type: " + o.GetType()); 
}

并将参数转换为动态类型,以绕过静态类型检查:

Foo((dynamic)something);

我同意Jon关于类名的操作散列。如果你想保留你的模式,你可能想要考虑使用"as"结构:

A a = o as A;
if (a != null) {
    a.Hop();
    return;
}
B b = o as B;
if (b != null) {
    b.Skip();
    return;
}
throw new ArgumentException("...");

区别在于当你使用if (foo is Bar) {((Bar)foo).Action();}你做了两次类型转换。现在编译器可能会优化,只做一次工作-但我不会指望它。