如何在C ++ / CLI中调用System :: Linq :: Expressions :: Expression的函数?

时间:2014-07-24 15:54:36

标签: lambda c++-cli

在我的C ++ / CLI应用程序中,我使用的是一个库(NHibernate),它有很多带有System :: Linq :: Expressions :: Expression的函数(比如QueryOver的Where()方法)。 / p>

在C#中,我可以写:

public IEnumerable< Cat > catsByName( string name )
{
    return session.QueryOver< Cat >()
                  .Where( c => c.Name == name ) // <--- this part
                  .List< Cat >();
}

显然我不能在C ++ / CLI中使用该语法,但我认为lambdas只是变成了匿名委托,我可以设置一个委托进行等效比较并将其传递给Where()。它不起作用。相反,我得到了这个编译错误:

1>cats.cpp(54): error C2664: 'NHibernate::IQueryOver<Cat ^,Cat ^> ^NHibernate::IQueryOver<Cat ^,Cat ^>::Where(System::Linq::Expressions::Expression<System::Func<Cat ^,bool> ^> ^)' : cannot convert argument 1 from 'System::Func<Cat ^,bool> ^' to 'NHibernate::Criterion::ICriterion ^'
1>          No user-defined-conversion operator available, or
1>          Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

如何调用这些功能?

1 个答案:

答案 0 :(得分:3)

首先要理解的是,lambda表达式不会转换为匿名委托。如果他们遵循某些规则,它们也可以是converted into expression trees,这是NHibernate的Where()方法所需要的,由其单个参数的类型指定:

System::Linq::Expressions::Expression< System::Func< T, bool > >

这要求Expression<>实例解析为函数T并返回bool(如果已编译)。

对于查询构建,NHibernate需要表达式树,以便它可以将它们转换为等效的SQL表达式/语句。实际的委托是(指向)一段可执行代码,它实际上可以在SQL语句中使用。

任何使用Expression<>的函数都需要一个表达式树,可能用于某些表达式转换或构建目的。这些功能不会成为代表。

但一切都没有丢失!如果你真的需要从C ++ / CLI调用一个Expression<>的函数,你可以!它们只是您可以构建的对象,就像其他任何东西一样。这是翻译的例子:

IEnumerable< Cat ^ > ^ catsByName( String ^ name )
{
    using namespace System::Linq::Expressions;

    auto catparam = Expression::Parameter( Cat::typeid, "cat" );
    auto catname = Expression::Property( catparam, "Name" );
    auto nameconstant = Expression::Constant( name );
    auto equaltoname = Expression::Equal( catname, nameconstant );
    auto lambdaexpr = Expression::Lambda< Func< Cat ^, bool > ^ >( equaltoname, gcnew cli::array< ParameterExpression ^ >{ catparam } );

    return session->QueryOver< Cat ^ >()->Where( lambdaexpr )->List< Cat ^ >();
}

所以你可以看到这很难看。您手动构建表达式树,而在C#中,编译器会为您执行此操作。另请注意,使用lambda表达式在C#中构建表达式树的主要好处之一是您可以获得属性的编译时类型检查。你不会在C ++ / CLI中得到它,因为你必须在运行时按名称获取类属性,这是通过字符串完成的。

最重要的是,在C ++ / CLI中确实可以调用带有Expression<>个参数的函数,但它比C#更难,乏味且容易出错,并且你真的得不到任何好处。如果有其他选择,您可能最好不要使用它。幸运的是,NHibernate也是如此。