Скажем, у меня есть класс вроде этого:
public sealed class Foo
{
public void Bar
{
// Do Bar Stuff
}
}
И я хочу расширить его, чтобы добавить что-то помимо того, что мог бы сделать метод расширения... Моя единственная опция - состав:
public class SuperFoo
{
private Foo _internalFoo;
public SuperFoo()
{
_internalFoo = new Foo();
}
public void Bar()
{
_internalFoo.Bar();
}
public void Baz()
{
// Do Baz Stuff
}
}
Пока это работает, это большая работа... однако у меня все еще возникает проблема:
public void AcceptsAFoo(Foo a)
Я могу передать в Foo здесь, но не супер Foo, потому что С# не знает, что SuperFoo действительно делает квалификацию в смысле Liskov Substitution... Это означает, что мой расширенный класс через композицию очень ограничен.
Таким образом, единственный способ исправить это - надеяться, что первоначальные дизайнеры API оставят интерфейс, лежащий вокруг:
public interface IFoo
{
public Bar();
}
public sealed class Foo : IFoo
{
// etc
}
Теперь я могу реализовать IFoo на SuperFoo (который, поскольку SuperFoo уже реализует Foo, это просто вопрос изменения подписи).
public class SuperFoo : IFoo
И в совершенном мире методы, которые потребляют Foo, будут потреблять IFoo:
public void AcceptsAFoo(IFoo a)
Теперь С# понимает взаимосвязь между SuperFoo и Foo из-за общего интерфейса, и все хорошо.
Большая проблема заключается в том, что .NET печатает множество классов, которые иногда могут быть полезными для расширения, и обычно они не реализуют общий интерфейс, поэтому методы API, которые принимают Foo, не будут принимать SuperFoo, и вы не может добавить перегрузку.
Итак, для всех поклонников композиции там... Как вы обойдете это ограничение?
Единственное, что я могу придумать, - публиковать публичный Foo публично, чтобы вы могли его иногда передавать, но это кажется грязным.