将强类型属性名称作为参数传递
我有一个IEnumerable
的集合,它被传递给一个填充DropDownList
的扩展方法。 我还想将DataValueField
和DataTextField
作为参数传递,但我希望它们是强类型的。
基本上,我不想为DataValueField
和DataTextField
参数传递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);
我的问题是,如何将强类型的DataValueField
和DataTextField
作为参数传递给populateDropDownList?
如果您只是尝试使用属性链,可以将参数更改为Expression
,然后提取所涉及的属性名称 – 您需要剖析Expression
得到…你希望Body
是一个表示属性访问的MemberExpression
。 如果你有多个( school.address.FirstLine
),那么一个成员访问的目标表达式将是另一个,等等。
从那里,您可以构建一个在DataValueField
(和DataTextField
)中使用的字符串。 当然,来电者仍然可以搞砸你:
myDropDownList.populateDropDownList(states, school => school.stateCode.GetHashCode().ToString(), school => school.stateName);
…但你可以检测它并抛出一个exception,你仍然可以为好的来电者提供重构保护。
根据Jon的回答和这篇文章,它给了我一个想法。 我将DataValueField
和DataTextField
作为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");