我正在为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);
编译器是否有理由无法在Map的扩展方法中推断出T1的类型?
答案 0 :(得分:9)
问题是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 :(得分:1)
我相信你希望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!")
..编译。