简体   繁体   English

lambda表达式内的泛型类型的访问属性

[英]Access property of a generic type inside lambda expression

The title may be ambiguous, but let me explain. 标题可能不明确,但让我解释一下。

I am working with MongoDb and with the c# driver for MongoDb, we can create a FilterDefinition<T> to create a filter to fetch data as follows : 我正在使用MongoDb和用于MongoDb的c#驱动程序,我们可以创建一个FilterDefinition<T>来创建一个过滤器来获取数据,如下所示:

var Filter = Builders<TestClass>.Filter.Eq(x => x.AnyProperty, Value);

I am trying to put this code inside a reusable generic method, so that i don't end up writing the same code again and again. 我试图将这段代码放入可重用的通用方法中,以免最终我不会一次又一次地写相同的代码。 I won't be including the entire function here, but inside the function, i am trying to do something as follows : 我不会在此处包括整个功能,但是在功能内部,我正在尝试执行以下操作:

var Filter = Builders<T>.FIlter.Eq(x => x.AnyProperty, value);

Now the drawbacks are : 现在的缺点是:

  • T is a generic type, meaning it doesn't have the property i am looking for. T是泛型类型,这意味着它没有我想要的属性。 So, i try to get the type of T and get the property that i am looking for by name, as follows : 因此,我尝试获取T的类型并按名称获取我要查找的属性,如下所示:

    ...FIlter.Eq(x => x.GetType().GetProperty(PropertyName), value)

This results in an exception : 这导致异常:

Unable to determine the serialization information for x => x.GetType().GetProperty("UserName"). 无法确定x => x.GetType()。GetProperty(“ UserName”)的序列化信息。 // UserName is the property name // UserName是属性名称

So, my question is, what can i do here for the generic type, which would be equivalent of x => x.PropertyName inside the lambda expression ? 所以,我的问题是,对于泛型类型,我该怎么办?这将等于lambda表达式中的x => x.PropertyName

Update 更新

Forgot to mention, i did try this : 忘了提,我确实尝试过这个:

var Filter = Builders<T>.FIlter.Eq("PropertName", value);

But it doesn't return the results from the database, where as this does : 但是它不会从数据库中返回结果,就像这样:

var Filter = Builders<MyClass>.FIlter.Eq("PropertName", value);

I really wonder why! 我真的很好奇为什么!

Update 2 更新2

Definition of Filter.Eq is as follows : Filter.Eq定义如下:

 public FilterDefinition<TDocument> Eq<TField>(FieldDefinition<TDocument, TField> field, TField value);

In the code 在代码中

FIlter.Eq(x => x.GetType().GetProperty(PropertyName), value) , my undersatnding is that Mongo driver is expecting an Expression , which is automatically created when you use the Metadata like in original case x => x.AnyProperty FIlter.Eq(x => x.GetType().GetProperty(PropertyName), value) ,我的不足是Mongo驱动程序需要一个Expression ,当您使用元数据时会自动创建一个Expression ,就像在原始情况下x => x.AnyProperty

In this case you need to explicitly supply MemberExpression as follows 在这种情况下,您需要显式提供MemberExpression ,如下所示

var parameterExpression = Expression.Parameter(typeof(T),"x");

var memberAccessExpression = Expression.MakeMemberAccess(parameterExpression, typeof(T).GetProperty("AnyProperty"));

Now you can supply to the FIlter.Eq value memberAccessExpression , in this case it will fail at run-time, if the AnyProperty is not part of type T , since its verified at the run-time. 现在,您可以提供给FIlter.EqmemberAccessExpression ,在这种情况下,如果AnyProperty不是type T一部分,则它将在运行时失败,因为它在运行时经过了验证。

In ExpressionTrees , this is the replacement of the x => x.AnyProperty ExpressionTrees ,这是x => x.AnyProperty

Edit 1: 编辑1:

Reviewing the Mongo DB Driver documents, following are the important details on the Definitions and Builders , there's an example as follows: 查看Mongo DB Driver文档,以下是Definitions和Builders的重要细节,下面是一个示例:

var builder = Builders<Widget>.Filter;
var filter = builder.Eq(widget => widget.X, 10) & builder.Lt(widget => widget.Y, 20);

Following is the definition of the FilterDefinitionBuilder.Eq , which expose the Eq and various other filters: 以下是FilterDefinitionBuilder.Eq的定义,该定义公开了Eq和其他各种过滤器:

public FilterDefinition<TDocument> Eq<TField>(Expression<Func<TDocument, TField>> field,TField value)

In this case, we need a generic type TDocument , which is the main class and TField , which is the type of the field on which filter is applied, therefore code in your case would be: 在这种情况下,我们需要一个通用类型TDocument ,它是主类, TField ,它是应用过滤器的字段的类型,因此您的情况下的代码将是:

var builder = Builders<T>.Filter;

// Use makeMemberAccessExpression created above
var filter = builder.Eq(Expression.Lambda<Func<T,string>>(makeMemberAccessExpression), "<stringValue>");

Important points: 要点:

  1. As it can be seen in the Mongo documentation, we have 2 generic types, TDocument and TField , here you are working with just one, so with the above code it will be restricted to string as type for TField , until and unless you make that also generic, which is your choice, otherwise all your fields shall be of specific type that you supply, which is string in this case 从Mongo文档中可以看出,我们有2个泛型类型TDocumentTField ,这里您只使用一种,所以使用上面的代码,它将限于字符串作为TField类型,直到并且除非您这样做也可以是通用的,这是您的选择,否则所有字段都应为您提供的特定类型,在这种情况下为字符串
  2. More important is the value shall be of type TField that you supply else it will not work and will fail at compile time 更重要的是,该值应为您提供的TField类型,否则它将不起作用并且在编译时将失败
  3. There's another overload, Eq<TField>(FieldDefinition<TDocument, TField>, TField) , which would work in a similar way, but since it expects FieldDefinition<TDocument, TField> , we need to supply the Expression<Func<TDocument,TField>> as part of the class, both overloads translates into similar code 还有另一个重载Eq<TField>(FieldDefinition<TDocument, TField>, TField) ,它的工作方式类似,但是由于它期望FieldDefinition<TDocument, TField> ,我们需要提供Expression<Func<TDocument,TField>>作为类的一部分,两个重载都转换为相似的代码

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM