【问题标题】:C# Select property with nameC# 选择带有名称的属性
【发布时间】:2019-08-06 20:59:05
【问题描述】:

我不知道如何正确表达这个问题,所以一开始就道歉。

我正在使用 MongoDb,在某些时候,我需要设计一个 lambda 表达式,如下所示:

...Set(g => g.Profile.First_Name, "Test");

现在,g 指的是一个名为 User 的类,它有一个类型为 Profile(不同的类)的属性,具有相同的名称 Profile。如您所见,在 lambda 表达式中,我选择了 First_Name 属性,然后将值 "Test" 传递给它。

我的问题: 有没有办法按名称选择属性?

更详细地说——这样的事情可能吗? :

 .... g.Profile. ("First_Name")

当我输入这个时,即使对我来说这听起来很荒谬,但我需要动态选择特定的属性,因此我需要通过它们的名称来选择它们。

我如何真正做到这一点?

我试过了:

g.Profile.GetType().GetProperty("First_Name")

但是好像不等同于g.Profile.First_Name

关于可以做什么的任何想法?

【问题讨论】:

  • 您需要提供更多关于您正在尝试做什么的信息。你提到了MongoDb。您是否尝试使用 MongoDb 驱动程序更新 MongoDb 中的文档?
  • 为什么不等价?似乎你对我来说是在正确的道路上......GetProperty 将返回一个PropertyInfo,然后你需要调用GetValueSetValue 如果你想用它做点什么(传递对象来修改, g.Profile 在这种情况下)。我会把它作为答案,但不确定你被困在哪里
  • @Steve,是的。文档结构是User类的结构,意味着文档具有与User类的属性相同的字段。现在,在User 类中,有一个Profile 类,也被定义为一个属性。我要做的是仅更新 Property 类的特定字段,该类位于 User 类中。这里的问题是,我只需要动态选择给定的属性。属性名称将作为字符串提供,因此我需要根据提供的名称找到一种方法来选择它们。
  • @BradleyDotNET 我认为问题在于Set 采用属性名称的 lambda 和将其设置为的值(然后在 Mongo-speak 中执行)。
  • 终于修好了!只是这样做了:.Set("Profile.First_Name", valueGoesHere) 和 MongoDb 按预期工作!

标签: c# reflection


【解决方案1】:

我可能实际上不想在这里使用反射。

g => ... 实际上不是一个 lambda 函数,而是一个 expression tree——它是一些用于描述一个过程的花哨的语法糖,在这种情况下,一个过程用于在给定 User 类型的记录的情况下获取某个属性。 MongoDB API 提供允许表达式的重载,因此您可以更优雅地编写 90% 的操作,但如果您确实需要动态,当然可以绕过它,例如:

var setName = Builders<User>.Update.Set(g => g.Profile.First_Name, "Test");

大致相当于:

var setName = Builders<User>.Update.Set("profile.first_name", "Test");

当然,如果您的属性、自定义约定等有 BsonProperty 属性,可以更改正在更新的 BSON 的路径。

现在,假设您不想对 BSON 路径进行硬编码。好吧,您可以生成动态表达式树,但它不是非常优雅或高性能。你会使用类似这样的东西:

ParameterExpression param = Expression.Parameter(typeof(User), "g");
Expression<Func<User, String>> expr =
    Expression.Lambda<Func<User, String>>(
        Expression.Property(
            Expression.Property(
                param,
                "Profile"
            ),
            "First_Name"
        ),
        new[] { param }
    );

 var setName = Builders<User>.Update.Set(expr, "Test");

【讨论】:

  • var setName = Builders&lt;User&gt;.Update.Set("profile.first_name", "Test"); 我想出了这部分,而且效果很好!谢谢
猜你喜欢
  • 2021-09-30
  • 2013-01-05
  • 1970-01-01
  • 2020-11-03
  • 1970-01-01
  • 2011-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多