简体   繁体   English

在编写具有多种类型的通用扩展方法时,键入推断问题

[英]Type inference problem when writing a generic extension method with more than one type

I am writing a generic extension method for IEnumerable for mapping a list of objects to another list of mapped objects. 我正在为IEnumerable编写一个通用扩展方法,用于将对象列表映射到另一个映射对象列表。 This is how I would like the method to work: 这就是我希望该方法工作的方式:

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

This is the method: 这是方法:

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

However articles.Map<ArticleViewModel>(_mappingEngine); 但是articles.Map<ArticleViewModel>(_mappingEngine); gives a compile error. 给出编译错误。 The problem is that the type inference for T1 doesn't work. 问题是T1的类型推断不起作用。 I have to explicitly call it like this instead: 我必须明确地这样称呼它:

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

If I create an extension method with only one parameter T1 like this: 如果我创建一个只有一个参数T1的扩展方法,如下所示:

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

Then I can call it like this, without having to specify T1: 然后我可以像这样调用它,而不必指定T1:

articles.DummyMap(_mappingEngine);

Is there are reason why the compiler can't infer the type of T1 in the extension method for Map? 有没有理由说编译器无法在Map的扩展方法中推断出T1的类型?

The problem is that the type inference for T1 doesn't work 问题是T1的类型推断不起作用

Actually, the problem isn't T1 - it is T2; 实际上,问题不是T1 - 它是T2; return types are not used in this inference. 此推断中不使用返回类型。 So you can't do that. 所以你不能这样做。 One option might be a fluent API, for example: 一个选项可能是一个流畅的API,例如:

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

with something like: 有类似的东西:

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>());
    }
}

assuming that the interface is something like: 假设接口是这样的:

public interface IMappingEngine {
    Func<T1, T2> Map<T1, T2>();
}

I believe you want C# compiler to infer type of T1 even if you provide T2 without providing T1. 我相信即使你提供T2而不提供T1,你也希望C#编译器推断T1的类型。

The point is you can use type inference, or just don't use it. 关键是你可以使用类型推断,或者只是不使用它。 You can't mix both worlds: 你不能混合两个世界:

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

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

This code doesn't compile, but: 此代码无法编译,但是:

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

    M("hello", "world!")

..compiles. ..compiles。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM