Search code examples
c#.netdesign-patternsinterfacecsla

Interface declaration for base class method to support IoC


So here is the code:

interface A<T>
{
    T Save();
}

interface B : A<B>
{
}

class BusinessBase<T>
{
    T Save();
}

class D<T, U> : BusinessBase<T>
    where T : BusinessBase<T>
    where U : B<U>
{
    new U Save()
    {
        base.Save(); // this is where the error is because T can't be converted to U
    }
}

class Concrete : D<Concrete , B>, B
{
}

So with all that what I am hoping to have is a base class that defines all the methods of A which are really just redirects to methods in C. But to support IoC and CSLA it has to be this way. So what I am looking for is to have the save in D return U not T so as to match the interface signature..

I have been staring at this for a while and can't seem to figure out what I am missing.


Solution

  • Ok so I just want to apologize for some of the bad code that was in my example. But hopefully if you looked at it for a while you could see where it went wrong. But here is the answer that I have come up with. I think there might be a better way in the conversion but I wanted a solution that didn't require me changing the BusinessBase class as that is a core CSLA component and not one I want to change. Here is the code I have come up with that is working:

    interface A<T>
    {
        T Save();
    }
    
    interface IConcreteInterface : A<IConcreteInterface>
    {
    }
    
    class BusinessBase<T>
        where T : BusinessBase<T>
    {
        public T Save()
        {
            return (T)this;
        }
    }
    
    class D<T, U> : BusinessBase<T>
        where T : BusinessBase<T>, A<U>
        where U : A<U>
    {
        public new U Save()
        {
            return (U)(object)base.Save();
        }
    }
    
    class ConcreteClass : D<ConcreteClass, IConcreteInterface>, IConcreteInterface
    {
    }
    

    The change that made it work was this: return (U)(object)base.Save();

    Before I was didn't put in the (U) cast in the sample because it woudn't compile like that. As there is no relationship between T and U that can be determined. So the only way around this is to cast the return T from Save to (object) which of course will then be capable of casting to anything.

    You notice I also added a type constraint for a little added protection against cast errors in that I am making sure that T is of type A and that U is of type A. That ensures that both types have the same interface.

    If someone has something prettier I am open to suggestions. But for now this is working and I feel somewhat good about it. You can do what I did which was at least require T to implement It isn't pretty and you can enforce a little more