0

I have an explicit conversion setup between two reference types.

class Car
{
    public void Foo(Car car)
    {

    }

    public static explicit operator Bike(Car car)
    {
        return new Bike();
    }

}

class Bike
{

}

If I invoke Foo and pass a type of Bike, then I must perform an explicit conversion.

            Car myCar = new Car();
            Bike bike = (Bike)myCar;            
            myCar.Foo(bike);//Error: Cannot convert from Bike to Car.

However, if I add an extension method, then explicit conversio is no longer required.

        public static void Foo(this Car car, Bike bike)
        {
            car.Foo(bike);//Success...
        }

Why is the extension method able to invoke Foo with a type of Bike implicitly?

P.Brian.Mackey
  • 43,228
  • 68
  • 238
  • 348
  • Because it can? Instance methods must come from the class itself (or a parent class.) Extension methods are just `static` methods in disguise, so the usual rules about argument convertibility apply, meaning a method with a first parameter of a given type can be invoked by types that are convertible to the type. (Note that I think you need to switch up which direction your conversion goes, but the point stands.) – dlev Jan 22 '13 at 22:49
  • 3
    You have specified a conversion from `Car` to `Bike` not the other way around. I am getting compiler errors on the lines you specify as successful. – Mike Zboray Jan 22 '13 at 22:50
  • I see the same error in both cases 'Argument type Bike is not assignable to parameter type Car'. – RJ Lohan Jan 22 '13 at 22:50

3 Answers3

6

Why is the extension method able to invoke Foo with a type of Bike implicitly?

It's not. The code you provided results in a compiler error.

At least one of the following is true:

  1. The code you provided here is not the code you're trying to compile.
  2. You have an implicit conversion in your code that you didn't add here.
  3. You just haven't actually compiled your code and haven't noticed that it won't compile.
Servy
  • 202,030
  • 26
  • 332
  • 449
4

Now that you've modified the code to show;

public static void Foo(this Car car, Bike bike)
{
    car.Foo(bike);//Success...
}

All you've done is create an ironic StackOverflowException. This method is now just calling itself recursively, not the implementation of Foo in Car.

TIP: Get yourself a copy of ReSharper - it'll put a nice circle-arrow icon on this line of code to show you what's going on without actually needing to compile or run it. :-)

RJ Lohan
  • 6,497
  • 3
  • 34
  • 54
0

Shouldn't your explicit conversion should be defined on Bike?

class Bike
{
    public static explicit operator Bike(Car car)
    {
        return new Bike();
    }
}

This allows:

Car myCar = new Car();
Bike myBike = (Bike) myCar;

If you want to be able to do this without specifying the conversion, you should use the implicit keyword.

Car myCar = new Car();
Bike myBike = myCar;

And finally, where you are getting the error //Error: Cannot convert from Bike to Car. This indicates you need the inverse conversion...

class Car
{
    // FROM Bike TO Car
    public static explicit operator Car(Bike bike)
    {
        return new Car();
    }
}
Fenton
  • 241,084
  • 71
  • 387
  • 401
  • The conversion operator (in either or both directions) can be defined within either `Bike` or `Car`, it doesn't matter which. – Servy Jan 23 '13 at 04:50
  • Except when you are trying to find your code as you can't F12 to it. This is one case where following the convention can be rather handy. – Fenton Jan 23 '13 at 09:38
  • In a large percentage of cases the person creating the conversions doesn't have control over at least one of the classes, so there is no choice as to where to put it. That's partly why there is no standard convention as to where to put them. – Servy Jan 23 '13 at 14:41