3

I was surprised to see today that this was possible, but I worry this must be discussed before.

public interface ICanAdd
{
    int Add(int x, int y);
}

// Note that MyAdder does NOT implement ICanAdd, 
// but it does define an Add method like the one in ICanAdd:
public class MyAdder
{
    public int Add(int x, int y)
    {
        return x + y;
    }
}

public class Program
{
    void Main()
    {
        var myAdder = new MyAdder();
        var iCanAdd = (ICanAdd)myAdder; //compiles, but for what sake?
        int sum = iCanAdd.Add(2, 2); //na, not game for it, cast had already failed
    }
}

The compiler will (rightly?) tell me that an explicit cast exists in the above situation. I was all thrilled to sense structural typing in there, but no run time it fails. So when is C# being ever helpful here? Any scenarios such casting would work? Whatever it is, I'm sure compiler beforehand knows myAdder is not ICanAdd, well technically.

nawfal
  • 70,104
  • 56
  • 326
  • 368
  • 2
    why downvoted? Am I having another brain fart session? – nawfal Apr 20 '13 at 10:21
  • Good question! Where's `adder` in `adder.Add` defined? Did you mean `iCanAdd`? – Sergey Kalinichenko Apr 20 '13 at 10:24
  • @dasblinkenlight yes surely. I will edit the typo :) But anyway that line is not hit. – nawfal Apr 20 '13 at 10:25
  • C# does support structural typing in one specific case: when you define anonymous types, it lets you treat types with identical structure as if they are the same, [like this](http://ideone.com/9D1Q7Y). – Sergey Kalinichenko Apr 20 '13 at 10:32
  • @dasblinkenlight that was awesome, never knew.. – nawfal Apr 20 '13 at 10:34
  • 2
    The compiler allows you to cast `MyAdder` to `ICanAdd` because it can't prove that no explicit conversion exists. For example, `myAdder` could be an instance of a derived type that implements the `ICanAdd` interface, and the cast would be allowed in that case. – Jeremy Todd Apr 20 '13 at 10:36
  • @JeremyTodd well it could be, but it is just a ***could be***. Does C# play that way? I think C# always have a strict, static, compile time validation isn't it? It doesn't allow many such *could be* situations, for example see this: http://stackoverflow.com/questions/14082431/cannot-pass-variable-of-type-conforming-to-generic-constraint – nawfal Apr 20 '13 at 10:45
  • @Alexander that is the answer, strange that C# lets it, and strange that until today I didn't know about it! Can you make it an answer? But I have no idea why C# lets it – nawfal Apr 20 '13 at 10:49
  • 1
    @nawfal The "could be" part is why it's an explicit rather than implicit conversion. If it knew for sure that it *is* a valid conversion, you wouldn't need to cast, you could just assign. You can view the need for an explicit cast as a signal from the compiler saying "Hey, this might not work. I'll give it a shot, but I hope you know what you're doing." – Jeremy Todd Apr 20 '13 at 10:51
  • @JeremyTodd that answers it from C#'s perspective, but I did not like that approach from the compiler. Can you make it an answer as well? – nawfal Apr 20 '13 at 10:54

2 Answers2

12

C# allows an explicit conversion from a class to an interface (even if the class doesn't implement that interface), because for all the compiler knows, a reference to a certain type might actually (the uncertainty is why it's an explicit rather than implicit conversion) be an instance of a derived type that does implement the interface. Extending your example, suppose you have:

public class DerivedAdder : MyAdder, ICanAdd
{
  int ICanAdd.Add(int x, int y)
  {
    return base.Add(x, y);
  }
}

...

MyAdder myAdder = new DerivedAdder();
var iCanAdd = (ICanAdd)myAdder; // Valid in this case
int sum = iCanAdd.Add(2, 2);    // sum = 4

If you check section 6.2.4 of the C# Specification, you'll see that if you mark your MyAdder class as sealed, the compiler will actually complain, because then it will know for sure that no conversion is possible, since no derived type could exist. But as long as it can't eliminate every last shred of doubt, it'll allow an explicit conversion.

nawfal
  • 70,104
  • 56
  • 326
  • 368
Jeremy Todd
  • 3,261
  • 1
  • 18
  • 17
  • I updated your answer with something from your comments, which made the point clear for me. Hope its ok. – nawfal Apr 20 '13 at 11:20
1

Casting class to interface is allowed by C# language specification. But for example if ICanAdd was a class - compilation would fail

Alexander
  • 4,153
  • 1
  • 24
  • 37