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

时间:2014-06-11 21:45:20

标签: c# generics extension-methods

我试图将以下方法转换为IEnumerable上的扩展方法:

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

现在它被称为:

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

但我想这样称呼它:

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

我试过这样做:

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

但我找不到类型或命名空间TSource,因为它未包含在方法的类型参数列表中。我可以让它像这样工作:

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

但是我必须这样称呼它:

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

我感觉不像sourceList.MapTo<TargetType>()那么清楚。

有没有办法做我想做的事?

1 个答案:

答案 0 :(得分:4)

调用中没有足够的信息来完全确定传递给MapTo的泛型类型参数,而C#不支持仅推断某些类型。您必须指定所有类型或不指定任何类型。

但是,您可以通过重新设计界面来解决这个问题。这只是一个解决方案:

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

现在你可以这样称呼它:

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

或者,如果您放弃使用扩展方法,可以这样做:

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

并称之为:

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

这些都不是特别优雅。如果您更喜欢这种语法而不是在每次调用时完全指定通用参数,那么这取决于您。