Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you use `switch` in C# to conditionally branch based on only a type parameter?

My context is that I'm building a simple factory method for creating instances of derived types of a given base type. The factory method only takes a type parameter, i.e. doesn't have any arguments. This is obviously possible with an if-else if construct:

public Vehicle Create<T>()
{
    if (typeof(T) == typeof(Car))
        return new Car(); // just an example; could be more complex logic.
    else if (typeof(T) == typeof(Truck))
        return new Truck(); // just an example; could be more complex logic.
    else
        throw new ArgumentException(
            $"The type {typeof(T).Name} is not known by this method.");
}

It's well-known by now how to use pattern matching in C# (as of C# 7.0) to branch based on the type of a variable but this doesn't work for a type parameter:

switch (T) { ... } // error: "'T' is a type, which is not valid in the given context"

or...

switch (typeof(T))
{
    case Car c: ... 
    // err: "An expression of type 'Type' cannot be handled by a pattern of type 'Car'"
}

So I'd like to know if it's possible to use switch to achieve the same result?


Research: I'm surprised this hasn't been asked before, but I can't find it. I found this post which has a name and a few answers that come pretty close but it's dealing with (numeric) value types and methods that have an argument of type T -- the generic type parameter. Similarly, this post also uses an argument.

like image 520
rory.ap Avatar asked Feb 03 '26 19:02

rory.ap


1 Answers

I know your question specifically asked about using the switch statement, but another alternative would be to create a dictionary of factories keyed on the type.

You should note that at this point, you are doing an operation similar to dependency injection. You are asking for a Vehicle of type X and risking a run-time error if the Create method does not have the information needed to Create a Vehicle of type X.

public class Car : Vehicle { }
public class Truck : Vehicle { }

public abstract class Vehicle
{
    private static readonly IReadOnlyDictionary<Type, Func<Vehicle>> vehicleFactories = new Dictionary<Type, Func<Vehicle>>
    {
        { typeof(Car), () => new Car() },
        { typeof(Truck), () => new Truck() }
    };

    public static Vehicle Create<T>() where T : Vehicle, new()
    {
        if (vehicleFactories.TryGetValue(typeof(T), out var factory))
        {
            return factory();
        }
        else
        {
            throw new ArgumentException(
                $"The type {typeof(T).Name} is not known by this method.");
        }
    }
}
like image 196
Grax32 Avatar answered Feb 06 '26 08:02

Grax32