views:

170

answers:

4

I have a method to which I pass an IEnumerable<TModel>. Then depending on the type of TModel, the method carries out a set of instructions as below:

    public void MyMethod<TModel>(IEnumerable<TModel> items) where TModel : class
    {
        int operationType;
        switch (typeof(TModel))
        {
            case typeof(MyModelOne):
                operationType = 1;
                break;
            case typeof(MyModelTwo):
                operationType = 2;
                break;
            case typeof(MyModelThree):
                operationType = 3;
                break;
            default:
                throw new Exception("The collection model passed to MyMethod is not recognized");
        }
        ...
    }

This doesnt work, I get the error:

There is no application variable or memeber 'TModel'

+6  A: 

You can't switch on a Type variable. Replace it with cascading if statements.

 if (typeof(TModel) == typeof(MyModelOne)) {
    operationType = 1;
 } else if (typeof(TModel) == typeof(MyModelTwo)) {
    operationType = 2;
 } // ...
Mehrdad Afshari
+1, but although typeof() is fast and lightweight, it's probably better and more readable to only get the type of the generic once. I.e. Type type = typeof(TModel); if(type == typeof(MyModelOne)) {}
GenericTypeTea
@GenericTypeTea: Yeah. By the time I was typing the second `if`, I had already written `typeof(TModel) == ...` and didn't bother going back :) Not likely to make a difference though.
Mehrdad Afshari
Nah, will mean diddly squat in the grand scheme of things. Just being picky because you beat me to the answer =P.
GenericTypeTea
+1  A: 

switch statements only work on constant values, such as strings, integers and other fundamental types. Type is not a constant value, so it can't be used in a switch block.

An equivalent operation is a block of if statements or using a dictionary with a Type used as the key.

Programming Hero
A: 

You can only switch on integral and string types. In this case, you'll have to use if/else.

Odrade
+1  A: 

The other answers here are true, but you should probably take a step back and look at why you're doing this. The whole point of generics is that they should be generic. If you are doing different things based on the type, then maybe a generic method isn't the way to go - maybe overloaded methods are right for you.

Or maybe the types that you want to accept can implement the same interface, and you can make calls on them based on the interface as opposed to checking the type manually. For example:

interface IDoesSomething
{
  void DoSomething();
}

void MyMethod<T>(IEnumerable<T> objects)
  where T : IDoesSomething
{
  foreach (T t in objects)
  {
    t.DoSomething();
  }
}
Joe Enos
http://weblogs.asp.net/alex_papadimoulis/archive/2005/05/25/408925.aspx
RossFabricant
Nice link there - I absolutely agree with him, although he may be a little too "grumpy", as he puts it. But I definitely encourage taking a step back whenever a problem just doesn't "feel" right, to make sure you're doing things right, as opposed to just doing things to get them done.
Joe Enos