views:

1499

answers:

9

I'm currently adding some new extended classes to this code:

foreach (BaseType b in CollectionOfExtendedTypes) {
  if (b is ExtendedType1) {
    ((ExtendedType1) b).foo = this;

  }
  else if (b is ExtendedType2) {
    ((ExtenedType2) b).foo = this;

  } 
  else {
    b.foo = this;

  }
}

and was curious if there is a way to use the is keyword functionality in a switch statement?

A: 

In C#, I believe the switch statement only works with integers and strings.

R4Y
+4  A: 

Nope. See

C# switch statement limitations - why?

harpo
+2  A: 

In C# it's not possible to use the "is" keyword as part of a switch statement. All case labels in a switch must evaluate to constant expressions. "is" is not convertible to a constant expression.

I definately feel the pain though when it comes to switching on types. Because really the solution you outlined works but it's a conveluted way of saying for x do y, and a do b. It would be much more natular to write it more like the following


TypeSwitch.Do(
    sender,
    TypeSwitch.Case<Button>(() => textBox1.Text = "Hit a Button"),
    TypeSwitch.Case<CheckBox>(x => textBox1.Text = "Checkbox is " + x.Checked),
    TypeSwitch.Default(() => textBox1.Text = "Not sure what is hovered over"));

Here's a blog post I wrote on how to achieve this functionality.

http://blogs.msdn.com/jaredpar/archive/2008/05/16/switching-on-types.aspx

JaredPar
A: 

You could add a method getType() to BaseType that is implemented by each concrete subclass to return a unique integral ID (possibly an enum) and switch on that, yes?

Owen
this seems natural to me as well but they are not my base classes to play around with. thx though
sre
A: 

Not really, switches match a variable (string or int (or enum) ) with a constant expression as the switch statement.

http://msdn.microsoft.com/en-us/library/06tc147t(VS.71).aspx

Fry
+1  A: 

While it is not possible to use switch statement for checking types, it is not impossible to reduce the problem to a more manageable codebase.

Depending on the specific situation and requirement I would consider.

  • Using a IDictionary<Type, T> to store the result in a dictionary. T could itself be a delegate that you can call on. This will work if you don't need to worry about inheritance - catering for inheritance will take a little more work.

  • Using the type name of the class (which is string) inside the switch statement. This uses switch (b.GetType().Name) and there is no option for deep inheritance structure.

Samuel Kim
+7  A: 

This really looks like a situation for a good inheritance implementation. If you override the appropriate methods in the derived classes, you may not need the checks in the loop at all.

Austin Salonen
A: 

There's another thing to think about besides the way that the compiler handles switch statements, and that's the functioning of the is operator. There's a big difference between:

if (obj is Foo)

and

if (obj.GetType() == typeof(Foo))

Despite the name, the is operator tells you if an object is compatible with a given type, not if it is of the given type. This leads to not-entirely-obvious bugs (though this one's pretty obvious) that look like:

if (obj is System.Object)
{
   //this will always execute
}
else if (obj is Foo)
{
   //this will never execute
}

Many of the suggestions here point you in the direction of using the object's type. That's fine if what you really want is logic associated with each type. But if that's the case, walk carefully when using the is operator.

Also: though you can't modify these base types, that doesn't mean that you can't use Owen's suggestion. You could implement extension methods:

public enum MyType { Foo, Bar, Baz };
public static class MyTypeExtension
{
   public static MyType GetMyType(this Foo o)
   {
      return MyType.Foo;
   }
   public static MyType GetMyType(this Bar o)
   {
      return MyType.Bar;
   }
   public static MyType GetMyType(this Baz o)
   {
      return MyType.Baz;
   }
}

Then you can use a switch statement:

switch (myObject.GetType())
{
   case MyType.Foo:
     // etc.
Robert Rossney
A: 
Jeffrey Hantin