Passing strongly typed property name as argument

心已入冬 提交于 2019-11-30 07:41:37

If you're only trying to use property chains, you could change the parameter to Expression<Func<T, string>> and then extract the property names involved - you'll need to dissect the Expression<TDelegate> you get... you'd expect that the Body will be a MemberExpression representing a property access. If you've got more than one (school.address.FirstLine) then the target expression of one member access will be another one, etc.

From that, you can build up a string to use in the DataValueField (and the DataTextField). Of course, the caller can still screw you over:

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

... but you can detect it and throw an exception, and you're still refactor-proof for good callers.

bflemi3

Based off Jon's answer and this post, it gave me an idea. I passed the DataValueField and DataTextField as Expression<Func<TObject, TProperty>> to my extension method. I created a method that accepts that expression and returns the MemberInfo for that property. Then all I have to call is .Name and I've got my string.

Oh, and I changed the extension method name to populate, it was ugly.

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.");
}

Called like so...

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

With what you were trying, even if you did get it to compile/run, it would still be wrong because the Value & Text fields would've been set to a value in the list instead of the property name (ie, DataValueField = "TX"; DataTextField = "Texas"; instead of DataValueField = "stateCode"; DataTextField = "stateName"; like you really want).

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");
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!