简体   繁体   English

如何在扩展方法中获取'this'参数的泛型类型参数?

[英]How can I get the generic type parameter of the 'this' parameter in an extension method?

I'm trying to convert the following method to an extension method on IEnumerable: 我正在尝试将以下方法转换为IEnumerable上的扩展方法:

private static IEnumerable<TTarget> MapList<TSource, TTarget>(IEnumerable<TSource> source)
{
    return source.Select(
            element =>
                _mapper.Map<TSource, TTarget>(element)
        ).ToList();
}

Right now it's called like this: 现在它被称为这样:

var sourceList = new List<SourceType>();
return MapList<SourceType, TargetType>(sourceList);

But I want to call it like this: 但我想这样称呼它:

var sourceList = new List<SourceType>();
return sourceList.MapTo<TargetType>();

I have tried doing this: 我试过这样做:

public static IEnumerable<TTarget> MapTo<TTarget>(this IEnumerable<TSource> source)
{
    return source.Select(
            element =>
                Mapper.Map<TSource, TTarget>(element)
        ).ToList();
}    

But I get type or namespace TSource not found since it's not included in the method's type parameter list. 但是我找不到类型或名称空间TSource因为它没有包含在方法的类型参数列表中。 I can make it work like this: 我可以让它像这样工作:

public static IEnumerable<TTarget> MapTo<TSource, TTarget>(this IEnumerable<TSource> source)
{
    return source.Select(
            element =>
                Mapper.Map<TSource, TTarget>(element)
        ).ToList();
}

But this I have to call it like this: 但是我必须这样称呼它:

var sourceList = new List<SourceType>();
sourceList.MapTo<SourceType, TargetType>();

Which I feel is not as clear as sourceList.MapTo<TargetType>() . 我觉得它不像sourceList.MapTo<TargetType>()那样清晰。

Is there any way to do what I want? 有什么办法可以做我想要的吗?

There's not enough information in the call to fully determine the generic type parameters to pass to MapTo , and C# doesn't support inferring only some of the types. 调用中没有足够的信息来完全确定传递给MapTo的泛型类型参数,而C#不支持仅推断某些类型。 You either have to specify all the types or none of them. 您必须指定所有类型或不指定任何类型。

However, you can get around this by redesigning your interface. 但是,您可以通过重新设计界面来解决这个问题。 Here's just one solution: 这只是一个解决方案:

public sealed class Mappable<TSource>
{
    private readonly IEnumerable<TSource> source;

    public Mappable(IEnumerable<TSource> source)
    {
        this.source = source;
    }

    public IEnumerable<TTarget> To<TTarget>()
    {
        return source.Select(
                element =>
                    Mapper.Map<TSource, TTarget>(element)
            ).ToList();
    }
}

public static class Extensions
{
    public static Mappable<TSource> Map<TSource>(this IEnumerable<TSource> source)
    {
        return new Mappable<TSource>(source);
    }
}

And now you can call it like this: 现在你可以这样称呼它:

var sourceList = new List<SourceType>();
var target = sourceList.Map().To<TargetType>();

Alternatively, if you give up on using extension methods, you can do it like this: 或者,如果您放弃使用扩展方法,您可以这样做:

public static class MapTo<TTarget>
{
    public static IEnumerable<TTarget> From<TSource>(IEnumerable<TSource> source)
    {
        return source.Select(
                element =>
                    Mapper.Map<TSource, TTarget>(element)
            ).ToList();
    }
}

And call it like this: 并称之为:

var sourceList = new List<SourceType>();
var target = MapTo<TargetType>.From(sourceList);

Neither of these are particularly elegant. 这些都不是特别优雅。 It's up to you if you prefer this syntax over fully specifying the generic parameters on each call. 如果您更喜欢这种语法而不是完全指定每次调用的通用参数,则由您决定。

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

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