Проблема вывода типа при написании универсального метода расширения с более чем одним типом - PullRequest
5 голосов
/ 09 марта 2011

Я пишу универсальный метод расширения для IEnumerable для отображения списка объектов в другой список отображаемых объектов.Вот как я хотел бы, чтобы метод работал:

IList<Article> articles = GetArticles();
return articles.Map<ArticleViewModel>(_mappingEngine);

Это метод:

public static IEnumerable<T2> Map<T1, T2>(this IEnumerable<T1> list, IMappingEngine engine)
{
    return list.Select(engine.Map<T1, T2>);
}

Однако articles.Map<ArticleViewModel>(_mappingEngine); выдает ошибку компиляции.Проблема в том, что вывод типа для T1 не работает.Я должен явным образом назвать его так:

articles.Map<Article, ArticleViewModel>(_mappingEngine);

Если я создаю метод расширения только с одним параметром T1, например:

public static IEnumerable<T1> DummyMap<T1>(this IEnumerable<T1> list, IMappingEngine engine)
{
    return list;
}

Тогдаможно назвать так без указания T1:

articles.DummyMap(_mappingEngine);

Есть ли причина, по которой компилятор не может определить тип T1 в методе расширения для Map?

Ответы [ 2 ]

9 голосов
/ 09 марта 2011

Проблема в том, что вывод типа для T1 не работает

На самом деле, проблема не в T1, а в T2;возвращаемые типы не используются в этом выводе.Так что ты не можешь этого сделать.Одним из вариантов может быть свободный API, например:

return articles.Map(_mappingEngine).To<SomeT2>();

с чем-то вроде:

public static MapProjection<T1> Map<T1>(this IEnumerable<T1> list, IMappingEngine engine)
{
    return new MapProjection<T1>(list, engine);
}
public class MapProjection<T1>
{
    private readonly IEnumerable<T1> list;
    private readonly IMappingEngine engine;
    internal MapProjection( IEnumerable<T1> list, IMappingEngine engine)
    {this.list = list; this.engine = engine;}

    public IEnumerable<T2> To<T2>()
    {
        return list.Select(engine.Map<T1, T2>());
    }
}

при условии, что интерфейс имеет что-то вроде:

public interface IMappingEngine {
    Func<T1, T2> Map<T1, T2>();
}
1 голос
/ 09 марта 2011

Я полагаю, что вы хотите, чтобы компилятор C # определял тип T1, даже если вы предоставляете T2 без предоставления T1.

Дело в том, что вы можете использовать вывод типа или просто не использовать его. Вы не можете смешивать оба мира:

    public void M<T, S>(T t, S s)
    {
    }

    M<string>("hello", "world!")

Этот код не компилируется, но:

    public void M<T, S>(T t, S s)
    {
    }

    M("hello", "world!")

.. компилирует.

...