Допустим, у меня есть такой класс:
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, потому что C # не имеет представления, что SuperFoo действительно подходит в смысле подстановки Лискова ... Это означает, что мой расширенный класс с помощью композиции имеет очень ограниченное использование.
Итак, единственный способ исправить это - надеяться, что разработчики оригинального 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)
Теперь C # понимает отношения между SuperFoo и Foo благодаря общему интерфейсу, и все хорошо.
Большая проблема в том, что .NET запечатывает множество классов, которые иногда приятно расширять, и они обычно не реализуют общий интерфейс, поэтому методы API, которые принимают Foo, не примут SuperFoo, и вы не могу добавить перегрузку.
Итак, для всех поклонников композиции там .... Как обойти это ограничение?
Единственное, о чем я могу думать, - это публично раскрыть внутренний Foo, чтобы вы могли время от времени передавать его, но это кажется грязным.