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

C# 将强类型属性名作为参数传递,c#,lambda,strong-typing,C#,Lambda,Strong Typing,我有一个IEnumerable集合,该集合正在传递给扩展 方法填充下拉列表。我也想通过考试 DataValueField和DataTextField作为参数,但我希望它们是 强类型 基本上,我不想为DataValueField和DataTextField参数传递string,这很容易出错 public static void populateDropDownList<T>(this DropDownList source, IEnumerable<T> d

我有一个
IEnumerable
集合,该集合正在传递给扩展 方法填充
下拉列表
。我也想通过考试
DataValueField
DataTextField
作为参数,但我希望它们是 强类型

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

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();
}
我的问题是,如何将强类型的
DataValueField
DataTextField
作为参数传递给populateDropDownList?

如果您只尝试使用属性链,可以将参数更改为
表达式
,然后提取所涉及的属性名称-您需要解析您得到的属性名。。。您可能希望,将是表示属性访问的。如果您有多个(
school.address.FirstLine
),则一个成员访问的目标表达式将是另一个,以此类推

由此,您可以构建一个字符串,用于
DataValueField
(以及
DataTextField
)。当然,打电话的人仍然可以欺骗你:

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

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

对于您所尝试的,即使您确实让它编译/运行了,它仍然是错误的,因为Value&Text字段将被设置为列表中的一个值,而不是属性名称(即,
DataValueField=“TX”;DataTextField=“Texas”
而不是您真正想要的
DataValueField=“stateCode”DataTextField=“stateName”

public static void populateDropDownList(此DropDownList源,
IEnumerable数据源,
Func dataValueField,
Func数据文本字段){
source.DataValueField=DataValueField();
source.DataTextField=DataTextField();
source.DataSource=数据源;
source.DataBind();
}
myDropDownList.populateDropDownList(州、,
“州代码”,
“州名”);

基于Jon的回答和帖子,它给了我一个想法。我将
数据值字段
数据文本字段
作为
表达式
传递给我的扩展方法。我创建了一个方法,该方法接受该表达式并返回该属性的
成员信息
。然后,我只需调用
。Name
,我已经获取我的
字符串

哦,我把扩展方法的名称改为
填充
,太难看了

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

我不明白这些字段是string类型的。我只是想让您知道,在惯用C语言中,您可以使用PascalCase将方法命名为
Populate
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");
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);