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

后端 未结 30 2848
梦毁少年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:09

    For built-in types, you can use the TypeCode enumeration. Please note that GetType() is kind of slow, but probably not relevant in most situations.

    switch (Type.GetTypeCode(someObject.GetType()))
    {
        case TypeCode.Boolean:
            break;
        case TypeCode.Byte:
            break;
        case TypeCode.Char:
            break;
    }
    

    For custom types, you can create your own enumeration, and either an interface or a base class with abstract property or method...

    Abstract class implementation of property

    public enum FooTypes { FooFighter, AbbreviatedFool, Fubar, Fugu };
    public abstract class Foo
    {
        public abstract FooTypes FooType { get; }
    }
    public class FooFighter : Foo
    {
        public override FooTypes FooType { get { return FooTypes.FooFighter; } }
    }
    

    Abstract class implementation of method

    public enum FooTypes { FooFighter, AbbreviatedFool, Fubar, Fugu };
    public abstract class Foo
    {
        public abstract FooTypes GetFooType();
    }
    public class FooFighter : Foo
    {
        public override FooTypes GetFooType() { return FooTypes.FooFighter; }
    }
    

    Interface implementation of property

    public enum FooTypes { FooFighter, AbbreviatedFool, Fubar, Fugu };
    public interface IFooType
    {
        FooTypes FooType { get; }
    }
    public class FooFighter : IFooType
    {
        public FooTypes FooType { get { return FooTypes.FooFighter; } }
    }
    

    Interface implementation of method

    public enum FooTypes { FooFighter, AbbreviatedFool, Fubar, Fugu };
    public interface IFooType
    {
        FooTypes GetFooType();
    }
    public class FooFighter : IFooType
    {
        public FooTypes GetFooType() { return FooTypes.FooFighter; }
    }
    

    One of my coworkers just told me about this too: This has the advantage that you can use it for literally any type of object, not just ones that you define. It has the disadvantage of being a bit larger and slower.

    First define a static class like this:

    public static class TypeEnumerator
    {
        public class TypeEnumeratorException : Exception
        {
            public Type unknownType { get; private set; }
            public TypeEnumeratorException(Type unknownType) : base()
            {
                this.unknownType = unknownType;
            }
        }
        public enum TypeEnumeratorTypes { _int, _string, _Foo, _TcpClient, };
        private static Dictionary typeDict;
        static TypeEnumerator()
        {
            typeDict = new Dictionary();
            typeDict[typeof(int)] = TypeEnumeratorTypes._int;
            typeDict[typeof(string)] = TypeEnumeratorTypes._string;
            typeDict[typeof(Foo)] = TypeEnumeratorTypes._Foo;
            typeDict[typeof(System.Net.Sockets.TcpClient)] = TypeEnumeratorTypes._TcpClient;
        }
        /// 
        /// Throws NullReferenceException and TypeEnumeratorException
        /// NullReferenceException
        /// TypeEnumeratorException
        public static TypeEnumeratorTypes EnumerateType(object theObject)
        {
            try
            {
                return typeDict[theObject.GetType()];
            }
            catch (KeyNotFoundException)
            {
                throw new TypeEnumeratorException(theObject.GetType());
            }
        }
    }
    

    And then you can use it like this:

    switch (TypeEnumerator.EnumerateType(someObject))
    {
        case TypeEnumerator.TypeEnumeratorTypes._int:
            break;
        case TypeEnumerator.TypeEnumeratorTypes._string:
            break;
    }
    

提交回复
热议问题