我们有一些通用代码。我们希望有一种方法可以接受Expression
,如下所示
public interface ISmallInterface
{
// ...
}
public interface IExample<TBase>
{
IQueryable<TBase> Where(Expression<Func<TBase, bool>> predicate);
}
public class SmallClass : ISmallInterface
{
// ...
}
从这里我们有了一些基本的实现
public abstract class AlphaBase<TBase> : IExample<TBase>
{
public IQueryable<TBase> Where(Expression<Func<TBase, bool>> predicate)
{
// ...
}
}
在我们的核心逻辑中,我们使用它来构建组件。然后在此Gamma
示例中,我们想要一个公开IExample<ISmallInterface>
的方法或属性。
public class Beta : AlphaBase<SmallClass>
{
// ...
}
public class Gamma
{
public IExample<ISmallInterface> GetThing()
{
var b = new Beta();
return b;
}
}
但是,这会导致编译器错误。
无法将类型“ Beta”隐式转换为“ IExample
”。存在显式转换(您是否缺少演员表?)
更改IExample
以使用协变类型参数可以解决此转换问题,但会破坏Where
方法。
public interface IExample<out TBase>
{
IQueryable<TBase> Where(Expression<Func<TBase, bool>> predicate);
}
给出编译器错误
无效方差:类型参数“ TBase”必须在“ IExample
.Where(Expression >)”上始终有效。 “ TBase”是协变的。
在我们的例子中,我们只能使用Func
个参数。
public interface IExample<out TBase>
{
IQueryable<TBase> Where(Func<TBase, bool> predicate);
}
public abstract class AlphaBase<TBase> : IExample<TBase>
{
public IQueryable<TBase> Where(Func<TBase, bool> predicate)
{
throw new NotImplementedException();
}
}
这将编译并运行。但是,使用Expression<Func<TBase, bool>>
会很方便。
是否有某种变通方法可以将Expression<Func<TBase, bool>>
与协变类型一起使用?
(dotnet核心2.2,如果那很重要,我认为是C#7.3)
答案 0 :(得分:0)
该解决方案非常简单,并且似乎遵循“ Linq方式”。
只需使用正确的签名创建扩展方法,然后在其中实现即可。现在界面中没有Where
方法。按照上面的示例,代码类似于
public interface IExample<out TBase>
{
// no Where, Count, or FirstOrDefault methods that accept Expression defined here
// This is a lazy loading method and doesn't execute the query
IQueryable<TBase> GetAll(ApplicationUser user);
}
public static class ExtensionMethods
{
public static IQueryable<TBase> Where<TBase>(
this IExample<TBase> repository,
ApplicationUser user,
Expression<Func<TBase, bool>> predicate)
{
return repository.GetAll(user).Where(predicate);
}
public static int Count<TBase>(
this IExample<TBase> repository,
ApplicationUser user,
Expression<Func<TBase, bool>> predicate)
{
return repository.GetAll(user).Count(predicate);
}
public static TBase FirstOrDefault<TBase>(
this IExample<TBase> repository,
ApplicationUser user,
Expression<Func<TBase, bool>> predicate)
{
return repository.GetAll(user).FirstOrDefault(predicate);
}
}