Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can one achieve the effect of overriding a base member with more specific type?

Tags:

c#

inheritance

I'm trying to figure out a way for a derived class to be made up of members that have more specific types than those specified in the abstract base class. Here is some code that works which does what I want, but does not follow the stipulations I mention. As a result, the client code (in Main) must use a cast on the "BarProperty" which is what I'm trying to avoid, I guess.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Stackoverflow
{
    class Program
    {
        static void Main(string[] args)
        {
            ConcreteFoo myFoo = new ConcreteFoo();
            myFoo.BarProperty = new ConcreteBar();

            ((ConcreteBar)myFoo.BarProperty).ConcreteBarPrint();

            Console.ReadKey();
        }
    }

    abstract class AbstractFoo
    {
        protected void FooMethod()
        {
            Console.WriteLine("The Foo method!");
        }

        public abstract AbstractBar BarProperty { get; set; }
    }

    class ConcreteFoo : AbstractFoo
    {
        private ConcreteBar _concreteBar;

        public override AbstractBar BarProperty
        {
            get
            {
                return _concreteBar;
            }
            set
            {
                _concreteBar = (ConcreteBar)value;
            }
        }
    }

    abstract class AbstractBar
    {
        protected void BarMethod()
        {
            Console.WriteLine("The Bar method!");
        }

    }

    class ConcreteBar : AbstractBar
    {
        public List<int> concreteBarIntList;

        public ConcreteBar()
        {
            concreteBarIntList = new List<int>();
            concreteBarIntList.Add(1);
            concreteBarIntList.Add(2);
            concreteBarIntList.Add(3);
        }

        public void ConcreteBarPrint()
        {
            foreach (int item in concreteBarIntList)
            {
                Console.WriteLine(item);
            }
        }

    }
}

What I'd like instead would be to do something like the code below, which of course doesn't compile because ConcreteFoo is trying to override BarProperty using a more specific type than AbstractFoo declared.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Stackoverflow
{
    class Program
    {
        static void Main(string[] args)
        {
            ConcreteFoo myFoo = new ConcreteFoo();
            myFoo.BarProperty = new ConcreteBar();

            myFoo.BarProperty.ConcreteBarPrint();

            Console.ReadKey();
        }
    }

    abstract class AbstractFoo
    {
        protected void FooMethod()
        {
            Console.WriteLine("The Foo method!");
        }

        public abstract AbstractBar BarProperty { get; set; }
    }

    class ConcreteFoo : AbstractFoo
    {
        private ConcreteBar _concreteBar;

        public override ConcreteBar BarProperty
        {
            get
            {
                return _concreteBar;
            }
            set
            {
                _concreteBar = (ConcreteBar)value;
            }
        }
    }

    abstract class AbstractBar
    {
        protected void BarMethod()
        {
            Console.WriteLine("The Bar method!");
        }

    }

    class ConcreteBar : AbstractBar
    {
        public List<int> concreteBarIntList;

        public ConcreteBar()
        {
            concreteBarIntList = new List<int>();
            concreteBarIntList.Add(1);
            concreteBarIntList.Add(2);
            concreteBarIntList.Add(3);
        }

        public void ConcreteBarPrint()
        {
            foreach (int item in concreteBarIntList)
            {
                Console.WriteLine(item);
            }
        }

    }
}

You may be thinking "rethink your design" but it's tricky because I'm trying to incorporate some third party code (without changing that code) which doesn't contain some much needed abstract/interface classes to give interchangeable facades to two very similar halves of the code base. As a result, I've basically had to write my entire program twice, with only minor changes in what types are being used. I need some way to handle either of two very similar types which unfortunately don't have an interface to demonstrate their similarity to the compiler.

like image 454
bubbleking Avatar asked Mar 06 '14 16:03

bubbleking


1 Answers

For the basic scenario, try giving BarProperty a generic type with a constraint:

public abstract class AbstractFoo<TBar> where TBar : AbstractBar
{
    public abstract TBar BarProperty { get; }
}

public class ConcreteFoo : AbstractFoo<ConcreteBar>
{
    public override ConcreteBar BarProperty { get { ...; } }
}

Based on additional comments, it sounds like the real challenge in this particular case is multiple classes that don't share a base type or interface, but have similar shapes and behaviors. In this case, one solution is to create a proxy class:

public class MyProxy
{
    private readonly Foo _foo;
    private readonly Bar _bar;

    public MyProxy(Foo foo)
    {
        this._foo = foo;
    }

    public MyProxy(Bar bar)
    {
        this._bar = bar;
    }

    public string SharedProperty1
    {
        get
        {
            if(this._foo != null)
            {
                return this._foo.SharedProperty1;
            }
            if(this._bar != null)
            {
                return this._bar.SharedProperty1;
            }
            throw new InvalidOperationException("Both underlying objects are null");
        }
    }
}
like image 103
Rex M Avatar answered Oct 22 '22 04:10

Rex M