C # - вопрос полиморфизма - PullRequest
1 голос
/ 06 мая 2011

У меня есть несколько классов, для которых я хотел бы использовать цепочечные методы, чтобы обеспечить свободный стиль конфигурации.

Например,

public class BaseFoo
{
    private bool _myProp = false;
    public [[[BaseFoo?]]] SetMyProperty()
    {
        this._myProp = true;
        return this;
    }
}

public class DerivedFoo : BaseFoo
{
    public bool _derivedProp = false;
    public DerivedFoo SetDerivedPropery()
    {
        this._derivedProp = true;
        return this;
    }
}

Проблема очевидна, когда я пытаюсь связать их вместе,как только я использую базовый метод, возвращается тип BaseFoo.Очевидно, я мог бы привести это обратно к DerivedFoo, но есть ли простой способ вернуть объект типа производного класса.

Единственный способ, которым я могу думать об этом - объединить конструкторы и передать в родительский типв первоначальный конструктор, но с использованием синтаксиса.

Другим способом было бы иметь подобные прокси-методы для каждого из подклассов, но возвращая производный тип.

 DerivedFoo foo = new DerivedFoo();
        foo.SetMyProperty().SetDerivedPropery(); // wont work because the SetMyProperty returns type of BaseFoo
        foo.SetDerivedPropery().SetMyProperty(); // works because I know i'm calling the method of the derived class first
        (foo.SetMyProperty() as DerivedFoo).SetDerivedPropery(); // works as i'm casting result of base method to derived type

есть идеи?

Заранее спасибо,

Сэм

Ответы [ 3 ]

8 голосов
/ 06 мая 2011

Как насчет генериков?

public class BaseFoo<TDerived> where TDerived : BaseFoo<TDerived>
{
    private bool _myProp = false;
    public TDerived SetMyProperty()
    {
        this._myProp = true;
        return (TDerived)this;
    }
}

public class DerivedFoo : BaseFoo<DerivedFoo>
{
    public bool _derivedProp = false;
    public DerivedFoo SetDerivedPropery()
    {
        this._derivedProp = true;
        return this;
    }
}

Но я действительно считаю, что связь между различными уровнями иерархии наследования является большой проблемой проектирования.
Я предлагаю вам иметьвзгляните на другие свободно распространяемые интерфейсы, такие как Fluent NHibernate, Rhino Mocks и т. д., чтобы увидеть, как «большие» парни делают это;.Мне кажется, это чище.

public static class FooFluentExtensions
{
    public static T SetMyProperty<T>(this T foo) where T : BaseFoo
    {
        foo.MyProp = true;
        return foo;
    }

    public static T SetDerivedPropery<T>(this T foo) where T : DerivedFoo
    {
        foo.DerivedProp = true;
        return foo;
    }
}

static void Main()
{
    DerivedFoo foo = new DerivedFoo();
    // works, because SetMyProperty returns DerivedFoo
    foo.SetMyProperty().SetDerivedPropery();

    BaseFoo baseFoo = new BaseFoo();
    baseFoo.SetMyProperty();

    // doesn't work (and that's correct), because SetMyProperty returns BaseFoo
    // baseFoo.SetMyProperty().SetDerivedPropery();
}

Вы можете заключить в капсулу каждый метод, которым вы хотите свободно владеть.

3 голосов
/ 06 мая 2011

Лично я ненавижу этот стиль кодирования.

Не можете ли вы сделать их свойства?Тогда вы можете сделать

DerivedFoo foo = new DerivedFoo
{
  MyProperty = true,
  DerivedProperty = true
};

Это намного чище и более читабельно.

1 голос
/ 06 мая 2011

Один из вариантов - сделать что-то вроде этого:

public class BaseFoo<T> where T : class
{
    private bool _myProp = false;
    public T SetMyProperty()
    {
        this._myProp = true;
        return this as T;
    }
}

    public class DerivedFoo : BaseFoo<DerivedFoo> { ... }

Но это зависит от вашего сценария.

...