Как я могу вернуть тип T из делегата Func? - PullRequest
0 голосов
/ 23 мая 2019

У меня есть класс, который определяет общий метод Add следующим образом:

public T Add(T item){

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

private Foo AddFoo(Foo f){
    //do foo adding stuff
}

private Bar AddBar(Bar b){
    //do bar adding stuff
}

// и т. Д., Еще много типов

Как я могу заставить свой метод Add вызывать правильный для моего типа метод?Кажется, что я мог бы использовать делегатов Func здесь, но я изо всех сил пытаюсь решить это.Большое спасибо!

Примечание: перегрузка Add для разных типов не является опцией, потому что класс реализует метод Add из интерфейса (и это не мой интерфейс для изменения)

Ответы [ 2 ]

2 голосов
/ 23 мая 2019

Почему бы не перегрузить метод Add?

public Foo Add(Foo f) { ... }
public Bar Add(Bar f) { ... }
public Baz Add(Baz f) { ... }
public Pony Add(Pony f) { ... }

Правильная перегрузка будет автоматически выбрана компилятором. Если объект передается в Add, который не является Foo, Bar, Baz или Pony, компилятор выдаст ошибку. Это не будет правдой, если вы используете дженерики и напишите свою рассылку.

Если вы используете дженерики:

public T Add<T>(T obj) { ... }

Тогда компилятор позволит вам написать:

Add(new Widget());

, что приведет к исключению runtime . Это решение не рекомендуется. Вы ничего не получаете и теряете преимущества системы типов.

Относительно вашего редактирования:

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

Я рекомендую вам исправить этот интерфейс. Этот интерфейс поврежден и должен быть исправлен. Обобщения не должны использоваться для создания универсального метода, который выполняет диспетчеризацию только при исключении статической системы типов. Использование вами обобщений здесь ничем не отличается от простого использования object в качестве типов возврата и параметров.

Если исправить этот интерфейс невозможно, перейдите к другому ответу.

0 голосов
/ 23 мая 2019

С C # 7.1 или новее вы можете реализовать его с сопоставлением с шаблоном как:

public T Add<T>(T item)
{
    switch (item)
    {
        case Foo a: return (T)(object) AddFoo(a);
        case Bar b: return (T)(object) AddBar(b);
        default: throw new InvalidOperationException(typeof(T) + " is not supported!");
    }
}
...