如何编写扩展方法来返回正在使用的类型?

时间:2015-02-21 21:58:28

标签: c# .net .net-4.5 extension-methods

我有一个允许用户关闭延迟加载的扩展方法。

public static IBaseEntityService<TEntity, TPrimaryKey> EnableLazyLoading<TEntity, TPrimaryKey>(
        this IBaseEntityService<TEntity, TPrimaryKey> baseService,
        bool enabled)  
        where TEntity :Entity<TPrimaryKey> where TPrimaryKey : struct
    {
        baseService.UnitOfWork.EnableLazyLoading(enabled);
        baseService.UnitOfWork.EnableProxyCreation(enabled);
        var type = baseService.GetType().;
        return (type)baseService;
    }

以下是基本界面的示例:

 public interface IBaseEntityService<TEntity,TPrimaryKey> : 
    IBaseService<TEntity, TPrimaryKey> 
    where TEntity: Entity<TPrimaryKey> where TPrimaryKey : struct
{

    TEntity FindByTenantId(Guid tenantId);
   IBaseEntitySpecification<TEntity,TPrimaryKey> Specification { get; } 
}

我们说我有这个实现IBaseEntityService<TEntity,TPrimaryKey>接口的服务:

public IUserService: IBaseEntityService<User,int>
{
      User FindByUserName(string username);
}

这是我想要实现的目标:

var user = _userService.EnableLazyLoading(false).FindByUserName("someUsername");

正如您在EnableLazyLoading(false)之后的示例中所见,我可以使用FindByUserName方法。目前,由于它只返回IBaseEntityService,我没有该选项。

我想确保扩展方法知道返回IUserService,因为它实现了IBaseEntityService。我知道它必须在某些时候强制转换它,我想避免为EnableLazyLoading

编写同一IUserService方法的具体实现

我想到了类似的东西,但似乎我可以做一些事情,而不必隐式调用Cast方法:

public static TEntityService Cast<TEntity, TPrimaryKey, TEntityService>(
            this IBaseEntityService<TEntity, TPrimaryKey> baseEntityService)
            where TEntity : Entity<TPrimaryKey>
            where TPrimaryKey : struct
            where TEntityService : IBaseEntityService<TEntity, TPrimaryKey>
        {
            return (TEntityService) baseEntityService;
        }

所以它可能会这样:

var user = _userService.EnableLazyLoading(false).Cast<IUserService>().FindByUserName("someUsername");

2 个答案:

答案 0 :(得分:4)

您可以将EnableLazyLoading的接收方设为约束为IBaseService的泛型类型。这是罗嗦的,但应该这样做。

public static TService EnableLazyLoading<TService, TEntity, TKey>(this TService service)
    where TService : IBaseService<TEntity, TKey>
    where TEntity : Entity<TKey>
    where TKey : struct
{
    // do stuff
    return service;
}

这样,您将获得实际的服务类型作为返回类型。我有一段时间没有做过C#,所以我可能会忘记一些重要的事情,但是IIRC这个工作得很好。

答案 1 :(得分:1)

Ben his answer提供的最佳解决方案是:

public static T EnableLazyLoading<T, TEntity, TKey>(
    this T @this,
    bool enabled)
                       where T       : IBaseService<TEntity, TKey>
                       where TEntity : Entity<TKey>
                       where TKey    : struct
{
    @this.UnitOfWork.EnableLazyLoading(enabled);
    @this.UnitOfWork.EnableProxyCreation(enabled);
    return @this;
}

另一种解决方案,更便宜但不是那么干净就是使用dynamic关键字:

public static dynamic EnableLazyLoading<TEntity, TPrimaryKey>(
    this IBaseEntityService<TEntity, TPrimaryKey> @this,
    bool enabled)  
                        where TEntity     : Entity<TPrimaryKey> 
                        where TPrimaryKey : struct
{
    @this.UnitOfWork.EnableLazyLoading(enabled);
    @this.UnitOfWork.EnableProxyCreation(enabled);
    return @this;
}

成本是您失去了IntelliSense的便利性,可能还有一些性能。