将强类型属性名称作为参数传递

我有一个IEnumerable的集合,它被传递给一个填充DropDownList的扩展方法。 我还想将DataValueFieldDataTextField作为参数传递,但我希望它们是强类型的。

基本上,我不想为DataValueFieldDataTextField参数传递string ,这很容易出错。

 public static void populateDropDownList(this DropDownList source, IEnumerable dataSource, Func dataValueField, Func dataTextField) { source.DataValueField = dataValueField; //<-- this is wrong source.DataTextField = dataTextField; //<-- this is wrong source.DataSource = dataSource; source.DataBind(); } 

像这样打电话……

 myDropDownList.populateDropDownList(states, school => school.stateCode, school => school.stateName); 

我的问题是,如何将强类型的DataValueFieldDataTextField作为参数传递给populateDropDownList?

如果您只是尝试使用属性链,可以将参数更改为Expression> ,然后提取所涉及的属性名称 – 您需要剖析Expression得到…你希望Body是一个表示属性访问的MemberExpression 。 如果你有多个( school.address.FirstLine ),那么一个成员访问的目标表达式将是另一个,等等。

从那里,您可以构建一个在DataValueField (和DataTextField )中使用的字符串。 当然,来电者仍然可以搞砸你:

 myDropDownList.populateDropDownList(states, school => school.stateCode.GetHashCode().ToString(), school => school.stateName); 

…但你可以检测它并抛出一个exception,你仍然可以为好的来电者提供重构保护。

根据Jon的回答和这篇文章,它给了我一个想法。 我将DataValueFieldDataTextField作为Expression>传递给我的扩展方法。 我创建了一个接受该表达式的方法,并返回该属性的MemberInfo 。 然后我要调用的是.Name ,我有我的string

哦,我改变了扩展方法名称来populate ,这很难看。

 public static void populate( this DropDownList source, IEnumerable dataSource, Expression> dataValueField, Expression> dataTextField) { source.DataValueField = getMemberInfo(dataValueField).Name; source.DataTextField = getMemberInfo(dataTextField).Name; source.DataSource = dataSource; source.DataBind(); } private static MemberInfo getMemberInfo(Expression> expression) { var member = expression.Body as MemberExpression; if(member != null) { return member.Member; } throw new ArgumentException("Member does not exist."); } 

像这样打电话……

 myDropDownList.populate(states, school => school.stateCode, school => school.stateName); 

根据您的尝试,即使您确实将其编译/运行,它仍然是错误的,因为值和文本字段将被设置为列表中的值而不是属性名称(即, DataValueField = "TX"; DataTextField = "Texas";而不是DataValueField = "stateCode"; DataTextField = "stateName";就像你真正想要的那样)。

 public static void populateDropDownList(this DropDownList source, IEnumerable dataSource, Func dataValueField, Func dataTextField) { source.DataValueField = dataValueField(); source.DataTextField = dataTextField(); source.DataSource = dataSource; source.DataBind(); } myDropDownList.populateDropDownList(states, "stateCode", "stateName");