0

I have a situation where I need to downcast twice in one procedure using :?>. I have a custom EventArgs class (which inherits System.EventArgs), and an instance of an abstract class within that custom EventArgs. Upon receiving the event, I need to downcast twice. Once for the custom EventArgs, and once for the abstract class within that custom EventArgs. I have to do this potentially millions of times a day, so I'm wondering if there's anything inherently slow about downcasting.

TeaDrivenDev
  • 6,591
  • 33
  • 50
user3685285
  • 6,066
  • 13
  • 54
  • 95
  • 4
    Have you benchmarked it? I certainly wouldn't *expect* it to be slow - 10 million times per day is only 115 times per second on average, which is a *really* small number for something like casting. – Jon Skeet Jul 13 '15 at 18:50
  • 3
    You're asking a highly subjective question. Slow is relative, so unless you can give a concrete comparison point its quite difficult to answer your question. – N_A Jul 13 '15 at 19:22
  • So for instance, exception handling is slow, and programmers are generally discouraged from using exceptions to handle main workflow. I was wondering whether downcasting had a similar issue. – user3685285 Jul 14 '15 at 13:41

1 Answers1

4

For grins, I put together the following little function:

let castToStream (o:Object) = o :?> Stream

and called it with the following code:

[<EntryPoint>]
let main argv = 
    let stm1 = new FileStream("output.tmp", FileMode.Create, FileAccess.ReadWrite, FileShare.Read)
    let obj = stm1 :> Object
    let stm2 = castToStream obj
    0 // return an integer exit code

When it is compiled, castToStream turns into this IL:

.method public static class [mscorlib]System.IO.Stream 
    castToStream(object o) cil managed
{
  // Code size       8 (0x8)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  unbox.any  [mscorlib]System.IO.Stream
  IL_0007:  ret
} // end of method Program::castToStream

which in this case is effectively 1 real instruction, unbox.any. Unbox.any for a reference type is equivalent to a castclass instruction. From the description, you'll take a one-time initial hit to load the type if it's not already loaded, then it's going to be a whatever magic is necessary to determine if the types are equivalent (likely using Type.IsAssignableFrom(), but I don't know for sure). However, unless your class hierarchy is super deep (and it shouldn't be), I would expect this to take microseconds on a typical machine.

For the curious, I initially had the code for castToStream inline, but the f# compiler saw through my shenanigans and removed all the casting entirely.

plinth
  • 48,267
  • 11
  • 78
  • 120