简体   繁体   中英

C# Is there any better way to use Switch-Case / If-Else on generic types

I am currently trying to get some casting on generic types done. So the base idea is to have a method which accepts a generic Type and does different stuff depending on which type gets passed in.

For simplicity reasons I will just showcase the use of float , bool and default

The setup looks something like this (where T is a generic type defined by the class itself):

protected T DoStuff(T value)
{
   switch (value) {
      case float floatValue:
         float result = DoFloatStuff(floatValue);
         switch (result) {
            case T output:
               return output;
         }
      case bool boolValue:
         bool result = DoBoolStuff(boolValue);
         switch (result) {
            case T output:
               return output;
         }
      default:
         // return value;
         DoRealGenericStuff(value) // Edited, since I just want to sort out some special cases
   }
}

Where DoFloatStuff and DoBoolStuff are just methods that have 1 parameter and a return type of their types respectively.

If I don't do it like that (I tried some typeof() casting before), the compiler always complains that it cannot cast from T to float and vice versa, even tho I made sure that would be the case with some Case-Switch / If-Else statements.

Does anybody know some better way to do this?

Thanks in advance, BOTHLine

Edit: Since a lot of people said kind of the same thing, that I either shouldn't use generics at all in a case like that or my methods would need to be more generic themselves.. My problem here is that I need to use 3rd party methods to handle the special cases I'm checking for (in this case the float and bool types). For the default case I already handled everything in a generic way. But for some defined types I just can't do that.

So to go a little more in detail why that's the case: I'm currently working on a Plugin for the "Unity Engine". Unity has built in methods to display types (kind of all primitive types and some Unity-specific types). I have a generic Wrapper class which should be able to contain any types. But then when I want to display the content of that wrapper in the GUI that Unity Editor offers, I have to use the built-in methods to display the primitives (something like UnityEditor.EditrGUI.FloatField() ). Without those methods I am never able to display anything. Anything else which can be broken down to those types can then be displayed in a more generic way.

So the base idea is to have a method which accepts a generic Type and does different stuff depending on which type gets passed in.

That is the wrong idea. It's not the way generics should be used. In such a case, you should use method overloading to create the DoStuff for each type individually:

float DoStuff(float value) {/* float implementation here */}
bool DoStuff(bool value) {/* bool implementation here */}
...

The point of generic is to enable you to write a code that will run the same on different types - so it should either be used where the type itself is irrelevant to the code (like in any generic collection) or can be executed with an interface or a base class all the acceptable types implement (or inherits). At this point, generics is usually only needed when you want a method to return a specific implementation of an interface (or base class).

Let the compiler sort it out for you:

protected void DoStuff(float v){}
protected void DoStuff(int v){}
// and so on
//and finally the default:
protected void DoStuff(object v){}

public void Work(T value)
{
    DoStuff(value)
}

This is not the short answer but it's the right way (by many standards). There might be a short answer but, if I were you I wouldn't bother.

This is the smell of a factory pattern. A generic should be, as the name suggests, generic and indifferent to the types if it is you can do something like this.

interface IDoStuffer<T>
{
    T DoStuff(T value)
}

class DoStuffFloat : IDoStuff<float>
{
    public float DoStuff(float value)
    {
        //Do your float stuff
    }
}

class DoStuffBool : IDoStuff<bool>
{
    public bool DoStuff(bool value)
    {
        //Do your bool stuff
    }
}

Then you can have a factory give you a correct implementation

class DoStuffFactory
{
    public IDoStuff<T> GetDoStuff<T>()
    {
        if(typeof(T) == typeof(float))
            return new DoStuffFloat();
        //And other types
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM