Метод перегрузки и полиморфизм - PullRequest
11 голосов
/ 07 февраля 2011
class Program
    {
        static void Main(string[] args)
        {
            List<A> myList = new List<A> {new A(), new B(), new C()};

            foreach (var a in myList)
            {
                Render(a);
            }

            Console.ReadKey();
        }

        private static void Render(A o)
        {
            Console.Write("A");
        }

        private static void Render(B b)
        {
            Console.Write("B");
        }

        private static void Render(C c)
        {
            Console.Write("C");
        }
    }

    class A
    {

    }

    class B : A
    {

    }

    class C : A
    {

    }

Вывод: AAA

Можно ли как-то использовать перегрузку метода, чтобы на выходе было: ABC?

Ответы [ 4 ]

14 голосов
/ 07 февраля 2011

Следующее должно быть сделано, где мы контролируем поведение при работе с типом в этом типе:

class A
{
    public virtual void Render()
    {
        Console.WriteLine("A");
    }
}

class B : A
{
    public override void Render()
    {
        Console.WriteLine("B");
    }
}

class C : A
{
    public override void Render()
    {
        Console.WriteLine("C");
    }
}

static void Main(string[] args)
{
    var myList = new List<A> { new A(), new B(), new C() };
    foreach (var a in myList)
    {
        a.Render();
    }
    Console.ReadKey();
}

И если вы хотите, чтобы определенное поведение типа было аддитивным к поведению его родителя, то вызовите метод, реализованный в базе, после выполнения вашей собственной логики, например:

class B : A
{
    public override void Render()
    {
        Console.WriteLine("B");
        base.Render();
    }
}
14 голосов
/ 07 февраля 2011

Вы можете использовать динамическую типизацию, если вы используете C # 4:

foreach (dynamic a in myList)
{
    Render(a);
}

В статической типизации разрешение перегрузки выполняется во время компиляции, а не во время выполнения.

Дляреализация, которая будет выбрана во время принятия решения, вы должны либо использовать переопределение вместо перегрузку , либо использовать динамическую типизацию, как указано выше.

6 голосов
/ 07 февраля 2011

Еще один способ сделать это с помощью шаблона посетителя : он позволяет вам достичь полиморфизма , подобного , используя двустороннюю систему вызова методов:

interface IRenderable
{
    AcceptForRender(Program renderer);
}

class Program
{
    static void Main(string[] args)
    {
        var p = new Program();
        var myList = new List<IRenderable> {new A(), new B(), new C()};

        foreach (var a in myList)
        {
            a.AcceptForRender(p);
        }

        Console.ReadKey();
    }

    public void Render(A o)
    {
        Console.Write("A");
    }

    public void Render(B b)
    {
        Console.Write("B");
    }

    public void Render(C c)
    {
        Console.Write("C");
    }
}

class A : IRenderable
{
    public void AcceptForRender(Program renderer)
    {
        renderer.Render(this);
    }
}

class B : IRenderable
{
    public void AcceptForRender(Program renderer)
    {
        renderer.Render(this);
    }
}

class C : IRenderable
{
    public void AcceptForRender(Program renderer)
    {
        renderer.Render(this);
    }
}

Преимущество этого подхода состоит в том, что он позволяет эффективно достигать полиморфизма (каждый тип обеспечивает правильную перегрузку, передавая строго типизированный this в Render внутри), сохраняя логику, которая не принадлежит вашим типам.сами (например, визуальная логика рендеринга).

2 голосов
/ 07 февраля 2011

Сделать A B C производным от базового (абстрактного) класса, определить в этом классе метод Render и правильно переопределить в каждом A B C. Вместо вызова Render(a), затем вызовите a.Render(), так должен работать полиморфизм.

...