Roslyn: Proposal: switch on System.Type

Created on 27 Jan 2016  路  16Comments  路  Source: dotnet/roslyn

When it comes to runtime type comparison, there are multiple ways to do so, it's more cumbersome if you want to do it multiple times with if else. it would be really nice if we could literally switch on System.Type or System.RuntimeTypeHandle and compiler choose the fastest way, like using TypeHandle.

Type type = ...;
switch(type) {
  case typeof(Foo): ... break;
  case typeof(Bar): ... break;
}
3 - Working Area-Language Design Language-C# New Language Feature - Pattern Matching

Most helpful comment

Since we have to fix the compiler crash, lets just make this work.

All 16 comments

It's planned that you can switch on type in C# 7.

I think it will look like this:

switch(baz)
{
    case Foo foo:
        foo.DoFoo();
        break;
    case Bar bar:
        bar.DoBar();
        break;
}

@GeirGrusom That's not what I'm talking about.

Well, it would be nice if types were first-class citizens, but that would require CLR support, I think.

@orthoxerox I even suspect that this behavior can be neatly implemented as an extension is operator (if that would be possible). So, no CLR support is required at all.

The CLR is fully capable of handling the logic. The question is how such a statement should be expanded. I'd imagine it would produce the same IL as a series of if/else statements since the IL switch opcode only works when the values are a range starting at 0 which the runtime type handle would not be.

Type type = obj.GetType();
switch (type)
{
    case typeof(Foo):
        Console.WriteLine("Foo!");
        break;
    case typeof(Bar):
        Console.WriteLine("Foo!");
        break;
    case typeof(Baz):
    default:
        Console.WriteLine("Baz or Something Else!");
        break;
    case typeof(Frob):
        Console.WriteLine("Frob!");
        break;
}

effectively equivalent to:

Type type = obj.GetType();
if (typeof(Foo).IsEquivalentTo(type))
{
    Console.WriteLine("Foo!");
}
else if (typeof(Bar).IsEquivalentTo(type))
{
    Console.WriteLine("Bar!");
}
else if (typeof(Frob).IsEquivalentTo(type))
{
    Console.WriteLine("Frob!");
}
else
{
    Console.WriteLine("Baz or Something Else!");
}

@HaloFour switch with pattern-matching already turns to mix of if, else and switch (at least this is what F# does). So I assume this can be done in a similar way. Also, I don't know about IsEquivalentTo but comparing TypeHandle causes no type load and will be emitted directly to IL (see the link in the opening post).

@alrz In IL it's all conditional branch opcodes, unless the condition meets the incredibly narrow requirements to make it work with switch. I assume that ADTs in F# have an incrementing tag field which do meet those requirements.

If if (typeof(Frob).TypeHandle.Equals(type)) is appreciably more efficient then sure, that's probably what the compiler should emit.

Should this only match exact types? What about derived types? Would case typeof(object) catch everything or only new object()? Either way it's going to surprise someone somewhere.

@drewnoakes That would be actually nice but then it will depend on the order and we might lose TypeHandle optimization.

Or it'll turn it into a dictionary lookup, similar to VB.net's Select Case

Seems you can do it in future branch
snip_20160410064405
But the compiler will crash when compiling it :(

@CnSimonChan I think that's because switch is already relaxed to accept any expression type (depending on the branch you're on) and this doesn't seem to be something that you'd get it "for free" via pattern-matching. So I think they should make it explicitly an error or consider implementing it.

@CnSimonChan Reported as #10459

Since we have to fix the compiler crash, lets just make this work.

A compelling feature I come a lot across with. I'd love to see this implemented.

Issue moved to dotnet/csharplang #356 via ZenHub

Was this page helpful?
0 / 5 - 0 ratings