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

当前回答

鉴于继承有助于将一个对象识别为不止一种类型,我认为切换可能会导致糟糕的模糊性。例如:

案例1

{
  string s = "a";
  if (s is string) Print("Foo");
  else if (s is object) Print("Bar");
}

案例2

{
  string s = "a";
  if (s is object) Print("Foo");
  else if (s is string) Print("Bar");
}

因为s是一个字符串和一个对象。 我认为当你编写一个switch(foo)时,你希望foo匹配一个且仅一个case语句。如果打开类型开关,那么编写case语句的顺序可能会改变整个switch语句的结果。我认为这是错误的。

您可以考虑对“typeswitch”语句的类型进行编译器检查,检查枚举类型是否彼此不继承。但这并不存在。

foo is T与foo. gettype () == typeof(T)不同!!

其他回答

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

是的——只需要使用c# 7中命名有点奇怪的“模式匹配”来匹配类或结构:

IObject concrete1 = new ObjectImplementation1();
IObject concrete2 = new ObjectImplementation2();

switch (concrete1)
{
    case ObjectImplementation1 c1: return "type 1";         
    case ObjectImplementation2 c2: return "type 2";         
}

这是一个混合来自JaredPar和VirtLink答案的备选答案,具有以下约束:

开关结构表现为函数,并将函数作为参数接收到case。 确保它被正确地构建,并且始终存在一个默认函数。 它在第一次匹配后返回(对于JaredPar答案为真,对于VirtLink不为真)。

用法:

 var result = 
   TSwitch<string>
     .On(val)
     .Case((string x) => "is a string")
     .Case((long x) => "is a long")
     .Default(_ => "what is it?");

代码:

public class TSwitch<TResult>
{
    class CaseInfo<T>
    {
        public Type Target { get; set; }
        public Func<object, T> Func { get; set; }
    }

    private object _source;
    private List<CaseInfo<TResult>> _cases;

    public static TSwitch<TResult> On(object source)
    {
        return new TSwitch<TResult> { 
            _source = source,
            _cases = new List<CaseInfo<TResult>>()
        };
    }

    public TResult Default(Func<object, TResult> defaultFunc)
    {
        var srcType = _source.GetType();
       foreach (var entry in _cases)
            if (entry.Target.IsAssignableFrom(srcType))
                return entry.Func(_source);

        return defaultFunc(_source);
    }

    public TSwitch<TResult> Case<TSource>(Func<TSource, TResult> func)
    {
        _cases.Add(new CaseInfo<TResult>
        {
            Func = x => func((TSource)x),
            Target = typeof(TSource)
        });
        return this;
    }
}

c# 8对模式匹配的增强使得这样做成为可能。在某些情况下,它做到了,而且更简洁。

        public Animal Animal { get; set; }
        ...
        var animalName = Animal switch
        {
            Cat cat => "Tom",
            Mouse mouse => "Jerry",
            _ => "unknown"
        };

我也会

使用方法重载(就像x0n),或者 使用子类(就像Pablo),或者 应用访问者模式。