Home > other >  Casting interface pointers with user-defined conversion operators
Casting interface pointers with user-defined conversion operators

Time:05-21

I have created an interface, that two different classes implement in C#. I have also implemented a user-defined conversion operator between the two classes. It is however not always called when interface pointers are used. I'm wondering why it's not, and if there's a way to make it so?

This is my code:

namespace InvalidCastReproducer
{
    class Program
    { 
        static void Main(string[] args)
        {
            MyType1 type1 = new MyType1();
            MyType2 type2;
            IMyType itype1 = new MyType1();
            IMyType itype2;

            type2 = (MyType2)type1;
            itype2 = (MyType2)type1;

            try
            {
                type2 = (MyType2)itype1;
            }
            catch (InvalidCastException iex)
            {
                Console.WriteLine(iex.Message);
            }

            try
            {
                itype2 = (MyType2)itype1;
            }
            catch (InvalidCastException iex)
            {
                Console.WriteLine(iex.Message);
            }
        }
    }

    public interface IMyType {}
    public class MyType1 : IMyType {}
    public class MyType2 : IMyType
    {
        public static explicit operator MyType2(MyType1 type1)
        {
            Console.WriteLine("User-defined conversion operator called.");
            return new MyType2();
        }
    }
}

I would have expected the user-defined conversion operator to be called all four times, but it is not. This is my output:

User-defined conversion operator called.
User-defined conversion operator called.
Unable to cast object of type 'InvalidCastReproducer.MyType1' to type 'InvalidCastReproducer.MyType2'.
Unable to cast object of type 'InvalidCastReproducer.MyType1' to type 'InvalidCastReproducer.MyType2'.

So it seems like when the type to cast from is a pointer of the interface type, it doesn't find the conversion operator, even if the instance is of the correct type.

I was considering implementing a conversion operator from IMyType to MyType2, but that isn't allowed by the compiler.

CodePudding user response:

Yes, explicit operators from interfaces or base types are not allowed in C#.

Basing on your code, you're converting rather than casting. You can achieve what you want using eg. contructor:

public class MyType2 : IMyType
{
    public MyType2()
    {
    }

    public MyType2(IMyType itype)
    {
        //...
    }
}

CodePudding user response:

I recommend creating a pattern matching factory

public class MyType2 : IMyType
{
    public static explicit operator MyType2(MyType1 type1)
    {
        Console.WriteLine("User-defined conversion operator called.");
        return new MyType2();
    }

    public static MyType2 FromMyType(IMyType value)
    {
        if (value is MyType2 t2) return t2;
        if (value is MyType1 t1) return (MyType2)t1;
        throw new ArgumentException($"Cannot convert from {value.GetType().Name}");
    }

to be called from the remaining program instead of a conversion

    static void Main(string[] args)
    {
        IMyType im1 = new MyType1();
        IMyType im2 = new MyType2();

        var m2_1 = MyType2.FromMyType(im1);
        var m2_2 = MyType2.FromMyType(im2);
    }
  • Related