C#Mongo DB驱动程序-方法调用不起作用的表达式
我试图通过发送一个表达式(C#mongo驱动程序版本2.7.3)来查询一些数据并投影到一个属性较少的类。 我试图理解为什么一个特定的表达式失败。 失败极大地限制了用户编写公共投影,并迫使用户在每次调用中内联编写投影。 这是一个简化的示例:C#Mongo DB驱动程序-方法调用不起作用的表达式,c#,database,mongodb,linq-expressions,mongodb-csharp-2.0,C#,Database,Mongodb,Linq Expressions,Mongodb Csharp 2.0,我试图通过发送一个表达式(C#mongo驱动程序版本2.7.3)来查询一些数据并投影到一个属性较少的类。 我试图理解为什么一个特定的表达式失败。 失败极大地限制了用户编写公共投影,并迫使用户在每次调用中内联编写投影。 这是一个简化的示例: private IMongoCollection<MyOriginalClass> _collection; class MyOriginalClass // imagine this class has many more properties
private IMongoCollection<MyOriginalClass> _collection;
class MyOriginalClass // imagine this class has many more properties
{
public int ID { get; set; }
}
class MyProjectedClass
{
public int ID { get; set; }
}
void DoWork()
{
var data1 = GetData(lib => new MyProjectedClass { ID = lib.ID }); // succeeds
var data2 = GetData(lib => ToProjected(lib)); // Fails in mongo driver: Index was out of range. Must be non-negative and less than the size of the collection.Parameter name: index
}
IEnumerable<MyProjectedClass> GetData(Expression<Func<MyOriginalClass, MyProjectedClass>> projection)
{
return _collection
.Aggregate()
.Project(Builders<MyOriginalClass>.Projection.Expression(projection))
.ToList();
}
MyProjectedClass ToProjected(MyOriginalClass orig)
{
return new MyProjectedClass {ID = orig.ID};
}
私人IMongoCollection\u collection;
类MyOriginalClass//想象这个类有更多的属性
{
公共int ID{get;set;}
}
类MyProjectedClass
{
公共int ID{get;set;}
}
无效销钉()
{
var data1=GetData(lib=>newmyprojectedclass{ID=lib.ID});//成功
var data2=GetData(lib=>ToProjected(lib));//在mongo驱动程序中失败:索引超出范围。必须为非负且小于集合的大小。参数名称:Index
}
IEnumerable GetData(表达式投影)
{
返回集合
.Aggregate()
.项目(建筑商.投影.表达式(投影))
.ToList();
}
MyProjectedClass到Projected(MyOriginalClass原始)
{
返回新的MyProjectedClass{ID=orig.ID};
}
首次(成功)使用是一个表达式,mongo驱动程序可以在运行时查看该表达式,从而知道ID=lib.ID。特别是这里
例如,Visual Studio允许在调试器下进行表达式可视化,对于第一个调试器,它显示:
.Lambda #Lambda1<System.Func`2[ConsoleApp1.Program+MyOriginalClass,ConsoleApp1.Program+MyProjectedClass]>(ConsoleApp1.Program+MyOriginalClass $lib)
{
.New ConsoleApp1.Program+MyProjectedClass(){
ID = $lib.ID
}
}
请熟悉,但第二个仍然是表达式,而不是Func(它未编译)。没错。我已经更新了我的答案,使其更加具体,这样编译表达式(Func)和MethodCallExpression之间就没有区别了?MethodCallExpression无法被遍历?这并没有什么区别,MethodCallExpression只是调用编译后的代码,因为表达式树非常浅,在运行时提供的信息很少。相比之下,NewExpression可能是一个更大的表达式树,包含更多信息。是的,MethodCallExpression不能被遍历(没有反编译)
.Lambda #Lambda1<System.Func`2[ConsoleApp1.Program+MyOriginalClass,ConsoleApp1.Program+MyProjectedClass]>(ConsoleApp1.Program+MyOriginalClass $lib)
{
.Call ConsoleApp1.Program.ToProjected($lib)
}
Expression<Func<MyOriginalClass, MyProjectedClass>> ToProjected()
{
return lib => new MyProjectedClass { ID = lib.ID };
}
var data2 = GetData(ToProjected());