Is there a better alternative than this to 'switch on type'?

后端 未结 30 2511
梦毁少年i
梦毁少年i 2020-11-22 03:28

Seeing as C# can\'t switch on a Type (which I gather wasn\'t added as a special case because is relationships mean that more than one distinct

相关标签:
30条回答
  • 2020-11-22 04:00

    Create an interface IFooable, then make your A and B classes to implement a common method, which in turn calls the corresponding method you want:

    interface IFooable
    {
        public void Foo();
    }
    
    class A : IFooable
    {
        //other methods ...
    
        public void Foo()
        {
            this.Hop();
        }
    }
    
    class B : IFooable
    {
        //other methods ...
    
        public void Foo()
        {
            this.Skip();
        }
    }
    
    class ProcessingClass
    {
        public void Foo(object o)
        {
            if (o == null)
                throw new NullRefferenceException("Null reference", "o");
    
            IFooable f = o as IFooable;
            if (f != null)
            {
                f.Foo();
            }
            else
            {
                throw new ArgumentException("Unexpected type: " + o.GetType());
            }
        }
    }
    

    Note, that it's better to use as instead first checking with is and then casting, as that way you make 2 casts, so it's more expensive.

    0 讨论(0)
  • 2020-11-22 04:00

    Should work with

    case type _:

    like:

    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;
    }
    
    0 讨论(0)
  • 2020-11-22 04:01

    Given inheritance facilitates an object to be recognized as more than one type, I think a switch could lead to bad ambiguity. For example:

    Case 1

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

    Case 2

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

    Because s is a string and an object. I think when you write a switch(foo) you expect foo to match one and only one of the case statements. With a switch on types, the order in which you write your case statements could possibly change the result of the whole switch statement. I think that would be wrong.

    You could think of a compiler-check on the types of a "typeswitch" statement, checking that the enumerated types do not inherit from each other. That doesn't exist though.

    foo is T is not the same as foo.GetType() == typeof(T)!!

    0 讨论(0)
  • 2020-11-22 04:01

    As Pablo suggests, interface approach is almost always the right thing to do to handle this. To really utilize switch, another alternative is to have a custom enum denoting your type in your classes.

    enum ObjectType { A, B, Default }
    
    interface IIdentifiable
    {
        ObjectType Type { get; };
    }
    class A : IIdentifiable
    {
        public ObjectType Type { get { return ObjectType.A; } }
    }
    
    class B : IIdentifiable
    {
        public ObjectType Type { get { return ObjectType.B; } }
    }
    
    void Foo(IIdentifiable o)
    {
        switch (o.Type)
        {
            case ObjectType.A:
            case ObjectType.B:
            //......
        }
    }
    

    This is kind of implemented in BCL too. One example is MemberInfo.MemberTypes, another is GetTypeCode for primitive types, like:

    void Foo(object o)
    {
        switch (Type.GetTypeCode(o.GetType())) // for IConvertible, just o.GetTypeCode()
        {
            case TypeCode.Int16:
            case TypeCode.Int32:
            //etc ......
        }
    }
    
    0 讨论(0)
  • 2020-11-22 04:01

    I use

        public T Store<T>()
        {
            Type t = typeof(T);
    
            if (t == typeof(CategoryDataStore))
                return (T)DependencyService.Get<IDataStore<ItemCategory>>();
            else
                return default(T);
        }
    
    0 讨论(0)
  • 2020-11-22 04:02

    You can create overloaded methods:

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

    And cast the argument to dynamic type in order to bypass static type checking:

    Foo((dynamic)something);
    
    0 讨论(0)
提交回复
热议问题