【发布时间】:2019-11-21 21:42:27
【问题描述】:
我们有一些通用代码。我们想要一个接受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 core 2.2,如果这很重要,我认为是 C#7.3)
【问题讨论】:
-
方差与类型推断大致相同。 (“变种”)。它必须在编译时知道并且 100% 确定它实际上是什么类型。使用 Variance,您可以让编译器自动添加必要的强制转换。所有这些推断的自动性都不存在于表达式树中,这必须手动完成。编译器将表达式的泛型解析为具体类型,但在协变的情况下,它不能说“它是这种类型”或“它是那种类型”。在某处进行了隐式转换。这必须在表达式中明确完成。这不是一个答案,也许是一个提示。
标签: c# covariance