如何为正在使用的类型 return 编写扩展方法?

How to write an extension method to return the type being used?

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

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 方法。目前,因为它只有 return 一个 IBaseEntityService,所以我没有那个选项。

我想确保扩展方法知道 return IUserService,因为它实现了 IBaseEntityService。我知道它必须在某个时候转换它,我想避免为 IUserService

编写相同 EnableLazyLoading 方法的特定实现

我想到了这样的事情,但似乎我可以做一些事情而不必隐式调用 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");

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

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 的便利性,并且可能失去了一些性能。

您可以将 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;
}

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