简体   繁体   中英

How to Define Extension Method for ICollection<T> where T : IMyInterface without Specifying T in the Method Definition

Background: I want to hook in business rules at the point that DTOs are being mapped to entities. I figured encapsulating the mapping into an extension method would be a good route.

IEntityDto is the interface that all DTOs that can be directly mapped to entities implement.

The single instance works fine:

public static TEntity MapTo<TEntity>(this IEntityDto dto)
{
    ... Run Business Rules that don't require db access ...
    return AutoMapper.Mapper.Map<TEntity>(dto);
}

I'd like to also extend ICollection the same way:

public static ICollection<TEntity> MapToCollection<TEntity>(this ICollection<IEntityDto> dtos)
{
    ... Run Business Rules that don't require db access ...
    return AutoMapper.Mapper.Map<ICollection<TEntity>>(dtos);
}

Unfortunately, MapToCollection does not show up on the context menu or compile when applied to an ICollection of IEntityDto.

What am I missing to get this to work? Do I need to just extend ICollection where T is IEntityDto? I'd prefer to not have to include the DTO type when calling the extension method.

public static ICollection<TEntity>MapToCollection<TDto,TEntity>(this ICollection<TDto> dtos) where TDto: IEntityDto
{
    ... Do Work and Return ...
}

The above works, but I was hoping to infer T from the collection.

Thanks!

You effectively need a method with a signature of

public static ICollection<TEntity> MapToCollection<TEntity, TEntityDto>(
    this ICollection<TEntityDto> dtos)
    where TEntityDto : IEntityDto

... but that would force you to specify both type arguments, which I understand you don't want to do.

What you can do instead is go in two hops, eg

public static class DtoExtensions
{
    public static CollectionMapper<TEntityDto> Map(this ICollection<TEntityDto> dtos)
        where TEntityDto : IEntityDto
    {
        return new CollectionMapper<TEntityDto>(dtos);
    }
}

public class CollectionMapper<TEntityDto> where TEntityDto : IEntityDto
{
    private readonly ICollection<TEntityDto> dtos;

    public CollectionMapper(ICollection<TEntityDto> dtos)
    {
        this.dtos = dtos;
    }

    public ICollection<TEntity> To<TEntity>()
    {
        // Business rules...
        return AutoMapper.Mapper.Map<ICollection<TEntity>>(dtos);
    }
}

You can now use:

var result = collection.Map().To<FooEntity>();

The Map call infers TEntityDto , and you specify TEntity in the To call.

I am assuming this happens because the variable that you want to call this extension method on is not actually of type ICollection<IEntityDto> but of type ICollection<MyEntityDto> for example.

Try this:

public static class ExtensionMethods
{
    public static ICollection<TEntity> MapToCollection<TEntity, TEntityDto>(
        this ICollection<TEntityDto> dtos) where TEntityDto : IEntityDto
    {
        return AutoMapper.Mapper.Map<ICollection<TEntity>>(dtos);
    }        
}

This method accepts a generic ICollection<TEntityDto> instead of ICollection<IEntityDto> which makes it work for cases like ICollection<MyEntityDto> .

Here is how you would use it:

Collection<MyEntityDto> collection = ...

var result = collection.MapToCollection<MyEntity, MyEntityDto>();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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