我有一个在表达式树中传递可选/默认参数的方法,如下所示:
Task<TResult> GetSingleAsync<TResult>(Expression<Func<TEntity, TResult>> selector = null);
我应该做的是,在忽略上述selector
参数的情况下检查上述方法时,将TResult
分配为TEntity
到我的方法中的选择器,基本上像{{ 1}},所以我正在尝试以下实现方式
selector = (TEntity) => TEntity
当我调用类似public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
private readonly DbSet<TEntity> _collection;
public async Task<TResult> GetSingleAsync<TResult>(Expression<Func<TEntity, TResult>> selector = null)
{
IQueryable<TEntity> query = this._collection;
if (selector == null) selector = (entity) => default(TResult);
return await query.Select(selector).SingleOrDefaultAsync();
}
}
之类的函数时,忽略默认参数GetSingleAsync<User>()
,但是selector
将选择器显示为 null ,有什么方法可以将值分配给selector = x => default(TResult)
时返回TEntity
作为TResult
吗?我已经尝试了以下所有方法,但也失败了
selector
答案 0 :(得分:1)
我认为您可能会根据自己的需求在此处选择几种方法。
TEntity
强制转换为TResult
。这将需要对TResult
进行类型约束,并在该约束上有点混乱。TEntity
是否为TResult
类型,如果是,则返回强制类型。否则,返回默认的TResult
。这个不需要类型约束,我认为这可能是没有约束的最佳选择。以下是我上面列出的选项的示例:
选项1:具有类型约束的投射。
public async Task<TResult> GetSingleAsync<TResult, TNewEntity>(Expression<Func<TNewEntity, TResult>> selector = null)
where TNewEntity: TEntity, TResult
{
IQueryable<TNewEntity> query = this._collection;
if (selector == null) selector = entity => (TResult) entity;
return await query.Select(selector).SingleOrDefaultAsync();
}
在这里,您看到了我在说的丑陋的类型约束。您必须引入一种新类型,以强制您的类约束为TResult
类型。
选项2:键入检查并进行投射。
public async Task<TResult> GetSingleAsync<TResult>(Expression<Func<TEntity, TResult>> selector = null)
{
IQueryable<TNewEntity> query = this._collection;
// I would use pattern matching here if I could, but unfortunately it looks like
// expression trees cannot have pattern matching so we have to box then cast.
if (selector == null) selector = entity => entity is TResult ? (TResult)(object) entity : default(TResult);
return await query.Select(selector).SingleOrDefaultAsync();
}
以此,它将尝试将实体转换为正确的类型,但是如果不能,它将返回TResult
的默认值,如果它是引用类型,则默认值为null
。仍然会遇到以前遇到的相同问题,但是,如果强制转换成功,则可能是您想要的。
选项3:。方法重载。
// New method with no selector. Notice the return type is now TEntity
public async Task<TEntity> GetSingleAsync(){
return GetSingleAsync(x => x); // This now works because TResult is TEntity.
}
// Original method, but now it requires the selector
public async Task<TResult> GetSingleAsync<TResult>(Expression<Func<TEntity, TResult>> selector)
{
IQueryable<TNewEntity> query = this._collection;
return await query.Select(selector).SingleOrDefaultAsync();
}
就个人而言,这似乎是您想要的选项以及我将要使用的选项。它实质上具有与默认参数相同的功能,但现在要求,如果未提供选择器,则查询将返回TEntity
。但是,我不知道问题的所有约束条件,也不知道是否需要默认参数。
注意:这类似于LINQ对可选选择器的作用。以下是一些ToDictionary
扩展名的来源:
public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer) {
return ToDictionary<TSource, TKey, TSource>(source, keySelector, IdentityFunction<TSource>.Instance, comparer);
}
public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector) {
return ToDictionary<TSource, TKey, TElement>(source, keySelector, elementSelector, null);
}
请注意,在第一种方法中,它们如何传入elementSelector
和每个TElement
的身份函数中,实际上只是由TSource
代替了。
结论:
这里没有列出其他选项,但是这些是我能想到的最好的选项。我测试了一下是否可以编译,但是还没有运行。