Let’s say I have a method that I want to make generic, and so far it had a big switch case of types.

For an simplified example,

switch (field.GetType()) {
case Type.Int: Method((int)x)...
case Type.NullInt: Method((int?)x)...
case Type.Long: Method((long)x)...

I’d like to be able to just call my GenericMethod<T>(field) instead and I’m wondering if this is possible and how would I go around doing it.

GenericMethod(field)

public void GenericMethod<T>(T field)

Can I use reflection to get a type and the pass it into the generic method somehow, is it possible to transform Type into <T>?

Can I have a method on the field object that will somehow give me a <T> type for use in my generic method?

Sorry for a confusing question, I’m not really sure how to phrase it correctly, but basically I want to get rid of switch cases and lots of manual coding when all I need is just the type (but that type can’t be passed as generic from parent class)

  • TwilightKiddy@programming.dev
    link
    fedilink
    arrow-up
    3
    ·
    edit-2
    4 months ago

    I don’t believe the first code sample is a valid C# code. Switch-case statements expect constants for case conditions and runtime types are not constants, obviously. What you can do is something like this:

    void MyMethod(object arg)
    {
        if (arg.GetType() == typeof(int))
            MyTypedMethod((int)arg);
        else if (arg.GetType() == typeof(int?))
            MyTypedMethod((int?)arg);
        else if (arg.GetType() == typeof(long))
            MyTypedMethod((long)arg);
    }
    

    This will work, but the problem here is that inheritance will fuck you up. All the types we check in this example are sealed and we don’t really have to worry about it in this case, but generally this code is… just bad.

    And yes, the correct way of implementing something like this is by using generic types. Starting from C# 7.0 we have this cool structure:

    void MyMethod<T>(T arg)
    {
        switch (arg)
        {
            case null:
                // Do something with null
                break;
            case int intArg:
                // Do something with intArg
                break;
            case long longArg:
                // Do something with longArg
                break;
        }
    }
    

    You’ll have to check for null separately, as you can’t use Nullable<> there, but overall, it looks much cleaner and handles inheritance properly for you.

    This is called pattern matching, you can read more about it here: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/patterns