3

我有一个集合IEnumerable<School>被传递给一个扩展方法,该方法填充一个DropDownList. 我也想传递 DataValueFieldandDataTextField作为参数,但我希望它们是强类型的。

基本上,我不想stringDataValueFieldandDataTextField参数传递 a,这很容易出错。

public static void populateDropDownList<T>(this DropDownList source,
        IEnumerable<T> dataSource,
        Func<T, string> dataValueField,
        Func<T, string> 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?

4

3 回答 3

5

根据乔恩的回答和这篇文章,它给了我一个想法。我将DataValueFieldand传递给我DataTextFieldExpression<Func<TObject, TProperty>>扩展方法。我创建了一个接受该表达式并返回该MemberInfo属性的方法。然后我只需要打电话给.Name我,我已经拿到了我的string.

哦,我将扩展方法名称更改为populate,这很难看。

public static void populate<TObject, TProperty>(
        this DropDownList source, 
        IEnumerable<TObject> dataSource, 
        Expression<Func<TObject, TProperty>> dataValueField, 
        Expression<Func<TObject, TProperty>> dataTextField) {
    source.DataValueField = getMemberInfo(dataValueField).Name;
    source.DataTextField = getMemberInfo(dataTextField).Name;
    source.DataSource = dataSource;
    source.DataBind();
}

private static MemberInfo getMemberInfo<TObject, TProperty>(Expression<Func<TObject, TProperty>> 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);
于 2012-10-25T18:18:31.110 回答
4

如果您只是尝试使用属性链,您可以将参数更改为,然后提取所涉及的属性Expression<Func<T, string>>名称 - 您需要剖析Expression<TDelegate>您获得的... . 如果您有多个 ( ),则一个成员访问的目标表达式将是另一个成员,等等。BodyMemberExpressionschool.address.FirstLine

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

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

...但是您可以检测到它并抛出异常,并且您仍然可以为好的调用者提供重构证明。

于 2012-10-25T17:48:25.980 回答
0

使用您正在尝试的内容,即使您确实让它编译/运行,它仍然是错误的,因为 Value & Text 字段将被设置为列表中的一个值而不是属性名称(即,DataValueField = "TX"; DataTextField = "Texas";而不是DataValueField = "stateCode"; DataTextField = "stateName";像你真的想要)。

public static void populateDropDownList<T>(this DropDownList source,
        IEnumerable<T> dataSource,
        Func<string> dataValueField,
        Func<string> dataTextField) {
    source.DataValueField = dataValueField();
    source.DataTextField = dataTextField();
    source.DataSource = dataSource;
    source.DataBind();
}

myDropDownList.populateDropDownList(states,
        "stateCode",
        "stateName");
于 2012-10-25T17:49:21.583 回答