0

Recently I've run into strange issue related to casting. Every discussion/post I've seen tends to revolve around using casting when one is sure about the object being casted plus a couple of details. I haven't however found what's the reasoning behind the code below:

class Program
{
    static void Main(string[] args)
    {
        var h = new SomeCommandHandler();
        var c = h as ICommandHandler<ICommand>; //this works as expected
        //var c = (ICommandHandler<ICommand>)h; //this throws - why?
    }

    interface ICommand { }
    class SomeCommand : ICommand { }

    interface ICommandHandler<I> where I : ICommand { }
    class SomeCommandHandler : ICommandHandler<SomeCommand> { }
}

So why the second call throws an exception? What's the difference between casting and as operator that I'm not aware of?

EDIT: It wpuld throw in the commented line above "Unhandled Exception: System.InvalidCastException: Unable to cast object of type 'SomeCommandHandler' to type 'ICommandHandler`1[ConsoleApplication1.Program+ICommand]'"

Filip Zawada
  • 824
  • 1
  • 7
  • 17

5 Answers5

9

Well, that's the whole entire difference right there. The as operator returns null if the object can't be cast to that type, and just casting produces an exception.

mqp
  • 70,359
  • 14
  • 95
  • 123
2

Others have already explained the difference between the direct cast throwing an exception and as returning null when the cast fails. In order to be able to make such a cast succeed you will need to make the generic interface contravariant:

interface ICommandHandler<out I> where I : ICommand { }

However, this might not be possible, depending on how the interface really looks (I am assuming that you are showing a stripped down version for brevity). If your interface contains method that accepts an argument of the type I this will not work; the type I must appear only in get-operations:

interface ICommandHandler<out I> where I : ICommand 
{
    void SetCommand(I n); // this would not be allowed...
    I GetCommand();       // ...but this would.
}
Fredrik Mörk
  • 155,851
  • 29
  • 291
  • 343
  • Guess. I need it as a parameter (void Execute(SomeCommand cmd)) so, as you said, covariance won't help me. Thanks for help anyway! – Filip Zawada Jan 31 '11 at 14:53
1

It throws an exception because h is of type SomeCommandHandler which is ICommandHandler<SomeCommand> and you try to cast it to ICommandHandler<ICommand> whis is a different type.

Itay Karo
  • 17,924
  • 4
  • 40
  • 58
0

The cast fails because an ICommandHandler<SomeCommand> is not an ICommandHandler<ICommand>. See here for more details & examples.

The as simply returns null when the instance is not of the specified type, whereas the cast throws an InvalidCastexception

Community
  • 1
  • 1
thecoop
  • 45,220
  • 19
  • 132
  • 189
0

the variable c is a is null. It doesn't throw because that's what using "as" means. In other words the instance h is Not an instance of ICommandHandler.

The next line throws because you're attempting to force a cast of an instance of SomCommandHandler to an instance of ICommandHandler

Make sense?

Shiv Kumar
  • 9,599
  • 2
  • 36
  • 38