鉴于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)不同!!

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

另一种方法是定义一个接口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();
    }
}

如果您正在使用c# 4,您可以利用新的动态功能来实现一个有趣的替代方案。我并不是说这样更好,事实上,它很可能会更慢,但它确实有一定的优雅。

class Thing
{

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

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

}

以及用法:

object aOrB = Get_AOrB();
Thing t = GetThing();
((dynamic)t).Foo(aorB);

这样做的原因是c# 4动态方法调用的重载是在运行时而不是编译时解决的。我最近写了一些关于这个想法的文章。再一次,我想重申,这可能比所有其他的建议都要差,我只是出于好奇才提供它。

这是一个混合来自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;
    }
}