简体   繁体   中英

Unable to explicitly cast a child class to another child class inside explicit implementation of interface in generic parent base class

I have the following code:

class Program
{
    static void Main(string[] args)
    {
        var first = new A();
        OtherClass.EnjoyLife(new OtherClass(first), OtherClass.Default);

        Console.ReadKey();
    }

    public interface IInterface
    {
        void DoStuff(IInterface obj);
    }


    public abstract class AbstractBaseClass<T> : IInterface where T : AbstractBaseClass<T>
    {
        internal abstract void DoStuff(T obj);

        void IInterface.DoStuff(IInterface obj) => DoStuff((T)obj);
    }

    public class A : AbstractBaseClass<A>
    {
        internal override void DoStuff(A obj)
        {
            Console.WriteLine($"Do {obj}");
        }
    }

    public class B : AbstractBaseClass<B>
    {
        internal override void DoStuff(B obj)
        {
            Console.WriteLine($"Do {obj}");
        }

        public static explicit operator A(B obj) => new A();
    }

    public class OtherClass
    {
        public static readonly OtherClass Default = new OtherClass();
        private IInterface foo;

        private OtherClass()
        {
            this.foo = new B();
        }

        public OtherClass(IInterface bar)
        {
            this.foo = bar;
        }

        public static void EnjoyLife(OtherClass left, OtherClass right)
        {
            left.foo.DoStuff(right.foo);
        }
    }
}

When I run it, I have an InvalidCastException: 'Unable to cast object of type 'B' to type 'A'.' being thrown when the explicit implementation of DoStuff is executed on AbstractBaseClass<T> . Why is it so even if an explicit cast from B to A is implemented on B ?

Quite interestingly, if I replace

void IInterface.DoStuff(IInterface obj) => DoStuff((T)obj);

by

void IInterface.DoStuff(IInterface obj) => DoStuff((T)obj.GetType().GetMethod("op_Explicit").Invoke(null, new[] { obj }));

then it works perfectly fine. But I cannot this solution for other reasons. I know the code is a bit circumvented but I don't see any reason why this should not work.

Based on what in the Main method and OtherClass, you should depend on abstraction, not on concrete classes while you override the DoStuff method For example

internal override void DoStuff(IInterface obj)
{
    Console.WriteLine($"Do {obj}");
}

but to do somthing like that you should remove the constraint on the abstract class

public abstract class AbstractBaseClass<T> : IInterface// where T : AbstractBaseClass<T>

and assign T to IInterface on concrete classes

public class A : AbstractBaseClass<IInterface>

I think if that will help you the abstract class here is useless you should implement the interface directly.

I need to know more and what the purpose of that design? because there are a lot of solutions if we know what you are trying to achieve.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM