使用Intellisense和编译时检查提取reflection的属性名称

好。 所以我有一些代码将winForm上的某些控件映射到对象中的某些属性,以便在数据发生某些事情时对控件执行某些操作。 一切都很好,工作得很好。 不是问题。 问题是,要将项添加到映射中,我调用的函数看起来像:

this.AddMapping(this.myControl,myObject,"myObjectPropertyName"); 

我遇到的问题是,在编译时很难说出上述行与下面的行之间的区别:

 this.AddMapping(this.myControl,myObject,"myObjectPropretyName"); 

由于最后一个参数是一个字符串,因此没有编译时检查或类似的任何操作会强制字符串本身实际上对应于给定对象上的有效属性名称。 此外,Refactor和“查找所有引用”之类的内容错过了这种引用,当属性名称发生变化时会导致欢闹。 所以我想知道的是,如果有一些方法可以更改函数,那么我传入的内容仍然是以某种方式表示属性名称的字符串,但是编译时会检查实际值是否进入。有人说我可以用表达式树做到这一点,但我已经阅读了它们,似乎没有看到连接。 我喜欢做类似的事情:

 this.AddMapping(this.myControl,myObject,myObject.myObjectPropertyName); 

甚至

 this.AddMapping(this.myControl,myObject.myObjectPropertyName); 

会很甜蜜!

有任何想法吗?

在3.5中,Expression是一种将成员名称指定为代码的方法; 你可以有:

 public void AddMapping(Control myControl, TObj myObject, Expression> mapping) {...} 

然后解析表达式树以获取值。 有点低效,但不是太糟糕。

这是示例代码:

  public void AddMapping( Control control, TSource source, Expression> mapping) { if (mapping.Body.NodeType != ExpressionType.MemberAccess) { throw new InvalidOperationException(); } MemberExpression me = (MemberExpression)mapping.Body; if (me.Expression != mapping.Parameters[0]) { throw new InvalidOperationException(); } string name = me.Member.Name; // TODO: do something with "control", "source" and "name", // maybe also using "me.Member" } 

叫来:

  AddMapping(myControl, foo, f => f.Bar); 

为了使基于Expression的lamda解决方法更容易,我将其作为扩展方法编写。

  public static string GetPropertyName(this object o, Expression> property) { var propertyInfo = (property.Body as MemberExpression).Member as PropertyInfo; if (propertyInfo == null) throw new ArgumentException("The lambda expression 'property' should point to a valid Property"); var propertyName = propertyInfo.Name; return propertyName; } 

像这样打电话

  class testclass { public string s { get; set; } public string s2 { get; set; } public int i { get; set; } } [TestMethod] public void TestMethod2() { testclass x = new testclass(); string nameOfPropertyS = this.GetPropertyName(() => xs); Assert.AreEqual("s", nameOfPropertyS); string nameOfPropertyI = x.GetPropertyName(() => xi); Assert.AreEqual("i", nameOfPropertyI); } 

好吧,使用扩展方法实际上是为了方便,因为事实上你可以在一个类上为anther类的属性调用该方法。 我相信它可以改进。

考虑使用lambdas甚至System.Linq.Expressions ,其中一个:

 extern void AddMapping(Control control, T target, Func mapping); extern void AddMapping(Control control, T target, Expression> mapping); 

然后用它来调用它

 this.AddMapping(this.myControl, myObject, (x => x.PropertyName)); 

如果需要在运行时拆分抽象语法树,请使用Expression参数来执行reflection性操作,例如将属性名称作为字符串获取; 或者,让代表完成捕获所需数据的工作。

你真的不应该将String文字作为属性名传递。 相反,您应该使用YourClass.PROPERTY_NAME_FOO

您应该将这些字符串声明为类中的consts。

 public const String PROPERTY_NAME_FOO = "any string, it really doesn't matter"; public const String PROPERTY_NAME_BAR = "some other name, it really doesn't matter"; 

或者,您根本不必担心字符串,只需要输入属性名称:

 public const int PROPERTY_NAME_FOO = 0; public const int PROPERTY_NAME_BAR = 1; //values don't matter, as long as they are unique 

这将阻止不引用有效属性的字符串进入函数调用。

Intelisense将能够向您显示您class级中的属性名称,作为自动完成的建议。

你在寻找什么称为静态reflection。 无耻的插件=> http://emiajnet.blogspot.com/2009/05/getting-fun-with-net-static-reflection.html这是一篇更好的文章: http : //www.lostechies.com/blogs/ gabrielschenker /存档/ 2009/02/03 /动态reflection抗静reflection.aspx