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

时间:2012-10-25 17:42:17

标签: c# lambda strong-typing

我有一个传递给扩展程序的IEnumerable<School>集合 填充DropDownList的方法。我也想通过 DataValueFieldDataTextField作为参数,但我希望它们成为 强烈打字。

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

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?

3 个答案:

答案 0 :(得分:4)

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

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

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

...但您可以检测到它并抛出异常,并且您仍然可以为好的来电者进行重构验证。

答案 1 :(得分:4)

根据Jon的回答和this帖子,它给了我一个想法。我将DataValueFieldDataTextField作为Expression<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);

答案 2 :(得分:0)

随着你的尝试,即使你确实得到它来编译/运行,它仍然是错的,因为价值&amp;文本字段将被设置为列表中的值而不是属性名称(即,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");