如何实现覆盖更具体类型的基础成员的效果?

时间:2014-03-06 16:09:17

标签: c# inheritance

我试图找出一种方法,使派生类由具有比抽象基类中指定的类型更具体类型的成员组成。这里有一些代码可以满足我的需求,但不符合我提到的规定。因此,客户端代码(在Main中)必须在“BarProperty”上使用强制转换,这是我想要避免的,我想。

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);
            }
        }

    }
}

我想要的是做类似下面的代码,当然不能编译,因为ConcreteFoo试图使用比AbstractFoo声明的更具体的类型来覆盖BarProperty。

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);
            }
        }

    }
}

您可能正在考虑“重新考虑您的设计”,但这很棘手,因为我正在尝试合并一些第三方代码(不更改代码),这些代码不包含一些非常需要的抽象/接口类,以便为两个代码提供可互换的外观非常相似的代码库的一半。结果,我基本上不得不两次编写我的整个程序,只使用了哪些类型的微小变化。我需要一些方法来处理两种非常相似的类型中的任何一种,遗憾的是它们没有接口来证明它们与编译器的相似性。

1 个答案:

答案 0 :(得分:8)

对于基本方案,请尝试BarProperty 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 { ...; } }
}

基于其他评论,听起来在这种特殊情况下真正的挑战是多个类不共享基本类型或接口,但具有相似的形状和行为。在这种情况下,一种解决方案是创建代理类

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");
        }
    }
}