Reputation: 4265
I have an extension method that allows a user to turn off lazy loading.
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;
}
Here is a sample of the base interface:
public interface IBaseEntityService<TEntity,TPrimaryKey> :
IBaseService<TEntity, TPrimaryKey>
where TEntity: Entity<TPrimaryKey> where TPrimaryKey : struct
{
TEntity FindByTenantId(Guid tenantId);
IBaseEntitySpecification<TEntity,TPrimaryKey> Specification { get; }
}
Let's say I have this service that implements the IBaseEntityService<TEntity,TPrimaryKey>
interface:
public IUserService: IBaseEntityService<User,int>
{
User FindByUserName(string username);
}
Here is what I want to achieve:
var user = _userService.EnableLazyLoading(false).FindByUserName("someUsername");
As you can see in my example after the EnableLazyLoading(false)
I can get to the FindByUserName
method. Currently, since it only returns an IBaseEntityService I do not have that option.
I want to ensure the extension method knows to return the IUserService
since it implements the IBaseEntityService
. I know it would have to cast it at some point and I want to avoid having to write a specific implementation of that same EnableLazyLoading
method for the IUserService
I thought of something like this, but it seems like I could do something without having to implicitly call a Cast method:
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;
}
So it might work like this:
var user = _userService.EnableLazyLoading(false).Cast<IUserService>().FindByUserName("someUsername");
Upvotes: 2
Views: 156
Reputation: 35891
The best solution, provided by Ben in his answer is:
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;
}
Another solution, cheaper but but not that clean is to use the dynamic
keyword:
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;
}
The cost is that you loose the convenience of IntelliSense, and possibly some performance.
Upvotes: 1
Reputation: 6059
You could just make the receiver of EnableLazyLoading
a generic type constrained to be an IBaseService
. It's wordy, but ought to do the trick.
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;
}
That way, you get the actual service type as the return type. I haven't done C# in a little while, so I may be forgetting something important, but IIRC this works just fine.
Upvotes: 4