Search code examples
c#casting

Why does this explicit cast not work when there is an implicit conversion defined?


I have a class with a defined implicit conversion to int:

public class SpeakerId
{
   private int value;
   public SpeakerId(int value) 
   { 
     this.value = value;
   }

   //integer conversions
   public static implicit operator SpeakerId(int value) => new SpeakerId(value);
   public static implicit operator int(SpeakerId obj) => obj.value;

   ...
}

With those conversions operators, I would think that this code would work:

var value = new SpeakerId(3);
var speakerId = (int)value;

but it doesn't; it causes a Specified cast is not valid error. Why would that be?

Update: My original code sample does work. The place where I get the error is when there's an intermediate cast to object, as you would have in a value converter:

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
  var speakerId = (int)value;
            
  return ...
}

or, easier to see:

  var value = new SpeakerId(3);
  object intermediate = value;
  var speakerId = (int)intermediate;

Solution

  • So (int) against an object is unboxing, not casting, and doesn't invoke any conversion operators1. You need to cast your object back to your reference type before you can try applying (int) to act as an actual cast:

    var speakerId = (int)(SpeakerId)value;
    

    Or you need to ensure you cast to int before it gets converted to object so that it is a boxed int and can be unboxed.


    Alternatively, if you don't know what the type of value is going to be but you're "sure" it'll have an appropriate conversion operator defined, you can force the lookup for a conversion to happen at runtime via dynamic:

    var speakerId = (int)(dynamic)value;
    

    1Except for some oddities around enums and their base types, unboxing has to be exactly to the type that was originally boxed.