鉴于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());
    }
}

当前回答

在比较了这里提供的f#特性的选项后,我发现f#对基于类型的切换有更好的支持(尽管我仍然坚持使用c#)。 你可能想看看这里和这里。

其他回答

你可以创建重载方法:

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

在c# 8之后,你可以使用新的开关使它更加简洁。通过使用discard选项_,你可以避免在你不需要的时候创建不必要的变量,像这样:

        return document switch {
            Invoice _ => "Is Invoice",
            ShippingList _ => "Is Shipping List",
            _ => "Unknown"
        };

Invoice和ShippingList是类,document是一个对象,可以是它们中的任何一个。

应该与

case type _:

如:

int i = 1;
bool b = true;
double d = 1.1;
object o = i; // whatever you want

switch (o)
{
    case int _:
        Answer.Content = "You got the int";
        break;
    case double _:
        Answer.Content = "You got the double";
        break;
    case bool _:
        Answer.Content = "You got the bool";
        break;
}

您正在寻找的是歧视性联合,这是f#的一个语言特性,但您可以通过使用我制作的名为OneOf的库来实现类似的效果

https://github.com/mcintyre321/OneOf

与switch(以及if和异常作为控制流)相比,它的主要优点是它是编译时安全的——没有默认处理程序或漏洞

void Foo(OneOf<A, B> o)
{
    o.Switch(
        a => a.Hop(),
        b => b.Skip()
    );
}

如果你在o中添加第三个项,你会得到一个编译器错误,因为你必须在switch调用中添加一个处理程序Func。

你也可以执行.Match来返回一个值,而不是执行一个语句:

double Area(OneOf<Square, Circle> o)
{
    return o.Match(
        square => square.Length * square.Length,
        circle => Math.PI * circle.Radius * circle.Radius
    );
}

我同意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();}你做了两次类型转换。现在编译器可能会优化,只做一次工作-但我不会指望它。