我有class X
,它实现了interface IX
。我也有专门为X的存储库类,它使用拉姆达expresions作为参数:我可以在.NET 3.5中实现协变,C#
public interface IX
{
}
public class X : IX
{
....
}
public class XRepository : IRepository<X>
{
public IEnumerable<X> Filter(Func<X, bool> filterFunc)
{
...
}
}
我需要让库类的工作与接口IX
,所以我加IRepository<IX>
的接口正在实施:
public class XRepository : IRepository<X>, IRepository<IX>
{
public IEnumerable<X> Filter(Func<X, bool> filterFunc)
{
...
}
public IEnumerable<IX> Filter(Func<IX, bool> filterFunc)
{
// I need to call the same filter method as above, but
// in order to do so I must convert the Func<IX, bool> to Func<X, bool>.
}
}
我必须将Func<IX, bool>
转换为Func<X, bool>
,但由于代码是使用.NET 3.5编写的C#3.0,因此我无法从4.0中引入的类型协方差中受益。
一个简单的解决方案可以使用Func<X, bool> newFunc = x => filterFunc(x);
,其中filterFunc
是Func<IX, bool>
类型。这会编译,有人可能会期望它运行良好,但我认为它不会。问题是我正在使用第三方框架来实现过滤器,即FluentNhibernate。我知道它使用表达式树来剥离传递到lambda表达式成员访问条件(如x => x.Name == "John"
)以构建本机SQL查询(如WHERE Name = 'John'
)。上述解决方案将产生一个不是这种表达式的Func<X, bool>
,我担心它将无法翻译。所以我需要创建相同的lambda表达式,但使用兼容类型。知道X实现了IX,显然Func<IX, bool>
中的任何代码都可以用于X
类型的对象。然而,对我来说这并不明显,我怎样才能执行这种转换。
我认为这可以使用表达式树来完成。我也担心我的表现会受到很大的影响。即使我决定对我的场景采用另一种解决方案,我仍然会欣赏将一个lambda翻译成另一个类似的方法的建议方法。
编辑:
为了澄清更多关于我遇到的问题,我写了下面的测试,模拟现实生活中的scenarion我面对:
Func<IX, bool> filter = y => y.Name == "John";
Func<X, bool> compatibleFilter = y => filter(y);
...
// Inside the Filter(Func<X, bool> filter method)
using(var session = nhibernateSessionFactory.OpenSession())
{
IEnumerable<X> xx = session.Query<X>().Where(z => compatibleFilter(z)).ToList();
}
如此,在ToList()
方法我收到以下异常
Unable to cast object of type 'NHibernate.Hql.Ast.HqlParameter' to type 'NHibernate.Hql.Ast.HqlBooleanExpression'.
这证实了我的假设,即Flunet NHiberante无法正确处理compatibleFilter参数。
所以我想要的是一种将Func转换为Func的方式,或者如John Skeet所建议的Expression<Func<IX, bool>>
至Expression<Func<X, bool>>
,它们具有相同的主体(y => y.Name = "John"
)。
编辑2:
最后我做了这一点!正确的方法不是使用Func<X, bool>
,而是使用Expression<Func<X, bool>>
。
Expression<Func<IX, bool>> filter = y => y.Name == "John Skeet";
Expression<Func<X, bool>> compatibleFilter = Expression.Lambda<Func<X, bool>>(
filter.Body,
filter.Parameters);
这产生了正确的SQL查询。IX,bool
待办事项你的意思是.NET 3.5?没有C#3.5这样的东西。 – 2012-03-11 20:24:02
是的,我的意思是.NET 3.5,但是我在某些地方见过C#3.0,我认为我可以将它应用于3.5。我纠正自己 – 2012-03-11 20:31:07
请参阅http://stackoverflow.com/questions/247621/what-are-the-correct-version-numbers-for-c – 2012-03-11 20:33:47