【问题标题】:Get class property name获取类属性名称
【发布时间】:2010-09-14 05:08:03
【问题描述】:

我的 winform 应用程序使用数据绑定收集数据。一切看起来都很好,除了我必须使用字符串将 propertytextedit 链接:

Me.TextEdit4.DataBindings.Add(New System.Windows.Forms.Binding("EditValue", Me.MyClassBindingSource, "MyClassProperty", True))

这很好,但是如果我更改类的属性名称,编译器显然不会警告我。

我希望能够通过反射得到属性名但是我不知道如何指定我想要的属性名(我只知道如何在类的所有属性之间进行迭代)

有什么想法吗?

【问题讨论】:

  • 只是为了确保:您想按名称获取属性,但名称可能已更改?这听起来像是无法真正解决的事情......

标签: .net reflection


【解决方案1】:

具有讽刺意味的是,反射希望您提供属性名称来获取它的信息:)

您可以创建自定义属性,将其应用于所需的属性。然后您将能够简单地获取具有此属性的属性的名称。

【讨论】:

    【解决方案2】:

    使用反射也会遇到同样的问题,因为要在所有类型的属性中找到正确的属性,您必须知道它的名称,对吗?

    【讨论】:

      【解决方案3】:

      你可以反映一个类型,但你不能反映它的成员,只能通过名称。

      如果这是唯一的属性,或者您确定可以通过索引找到它的顺序,但一般来说字符串是最安全的方法。

      我相信更改名称会导致运行时异常,但我不是 100% 确定,在这两种情况下这可能是最好的可能性。

      假设没有自动发生异常,您可以添加一个 Debug.Assert 来检查该名称的属性是否存在,但同样只是运行时。

      【讨论】:

        【解决方案4】:

        1) 指定您想要的确切属性名称并保持这种方式

        2) 编写一个涉及该属性名称的测试。

        【讨论】:

          【解决方案5】:

          下面是我所说的一个例子:

          [AttributeUsage(AttributeTargets.Property)]
          class TextProperyAttribute: Attribute
          {}
          
          class MyTextBox
          {
              [TextPropery]
              public string Text { get; set;}
              public int Foo { get; set;}
              public double Bar { get; set;}
          }
          
          
          static string GetTextProperty(Type type)
          {
              foreach (PropertyInfo info in type.GetProperties())
              {
                  if (info.GetCustomAttributes(typeof(TextProperyAttribute), true).Length > 0)
                  {
                      return info.Name;
                  }
              }
          
              return null;
          }
          
          ...
          
          Type type = typeof (MyTextBox);
          
          string name = GetTextProperty(type);
          
          Console.WriteLine(name); // Prints "Text"
          

          【讨论】:

          • 该死,你打败了我……我正要发布一个例子。 :-/
          • 文字差不多,我可以补充一下。
          • 康拉德鲁道夫,今天我因为不明原因失去了大约 200 个代表,给我一个机会 :)。去投票吧!
          • 但如果我理解正确,那么我需要为每个属性提供一个类和一个方法:FooPropertyAttribute 和 GetFooProperty、BarPropertyAttribute 和 GetBarAttribute。这是正确的吗?
          • MiguelE,不,您需要 1 个属性来标记可绑定属性。如果您需要其他信息,可以将其存储在该属性中。
          【解决方案6】:

          如果您使用的是 C# 3.0,有一种方法可以动态获取属性名称,而无需对其进行硬编码。

          private string GetPropertyName<TValue>(Expression<Func<BindingSourceType, TValue>> propertySelector)
          {
              var memberExpression = propertySelector.Body as MemberExpression;
              return memberExpression != null 
                     ? memberExpression.Member.Name 
                     : string.empty;
          }
          

          其中BindingSourceType 是您的数据源对象实例的类名。

          然后,您可以使用 lambda 表达式以强类型方式选择要绑定的属性:

          this.textBox.DataBindings.Add(GetPropertyName(o => o.MyClassProperty),
                                        this.myDataSourceObject,
                                        "Text");
          

          它将允许您安全地重构您的代码,而不会破坏您所有的数据绑定内容。但就性能而言,使用表达式树与使用反射是一样的。

          前面的代码非常丑陋且未经检查,但你明白了。

          【讨论】:

          • 不错,但是它在 UI 和数据源对象之间创建了编译依赖。
          • 这应该不是问题...我不确定为什么 UI 不能知道它显示的对象类型。在 MVP/MVC 中,几乎总是如此,即使我们使用表示模型。但是是的,如果你不知道对象的类型,你就不能使用这个解决方案。
          • 我同意强类型是一件好事。然而,数据绑定通常依赖于文本名称。通常您通过某种 GUI 或在配置文件(例如 XAML)中进行设置。虽然你的解决方案很酷!
          • 看来这里的提问者需要保持用于引用属性名称和属性名称的同步字符串。他显然知道他绑定了什么样的对象:)
          • VB 编译器使用额外级别构建 lambda 表达式,因此 VB 等效项需要从 propertySelector.Body 获取 UnaryExpression,然后从 unary.Operand 获取 MemberExpression。
          猜你喜欢
          • 2021-12-04
          • 2014-06-27
          • 2012-01-08
          • 2010-10-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-15
          相关资源
          最近更新 更多