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

当前回答

我使用

    public T Store<T>()
    {
        Type t = typeof(T);

        if (t == typeof(CategoryDataStore))
            return (T)DependencyService.Get<IDataStore<ItemCategory>>();
        else
            return default(T);
    }

其他回答

一种选择是使用一个从Type到Action(或其他委托)的字典。根据类型查找操作,然后执行它。我以前在工厂用过这个。

另一种方法是定义一个接口IThing,然后在两个类中实现它 以下是片段:

public interface IThing
{
    void Move();
}

public class ThingA : IThing
{
    public void Move()
    {
        Hop();
    }

    public void Hop(){  
        //Implementation of Hop 
    }

}

public class ThingA : IThing
{
    public void Move()
    {
        Skip();
    }

    public void Skip(){ 
        //Implementation of Skip    
    }

}

public class Foo
{
    static void Main(String[] args)
    {

    }

    private void Foo(IThing a)
    {
        a.Move();
    }
}

你可以创建重载方法:

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

您正在寻找的是歧视性联合,这是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
    );
}

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

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

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