c# - dinamico - lenguajes fuertemente y débilmente tipados
Pasar el nombre de propiedad fuertemente tipado como argumento (3)
Con lo que estabas intentando, incluso si lo hicieras compilar / ejecutar, seguiría siendo incorrecto porque los campos de Valor y Texto se habrían establecido en un valor en la lista en lugar del nombre de la propiedad (es decir, DataValueField = "TX"; DataTextField = "Texas"; lugar de DataValueField = "stateCode"; DataTextField = "stateName"; como realmente desea).
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");
Tengo una colección de IEnumerable<School> que se está IEnumerable<School> a un método de extensión que rellena DropDownList . También me gustaría pasar DataValueField y DataTextField como argumento, pero quería que estuvieran fuertemente tipados.
Básicamente, no quiero pasar una string para los argumentos DataValueField y DataTextField , es propenso a errores.
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();
}
Llamado así ...
myDropDownList.populateDropDownList(states,
school => school.stateCode,
school => school.stateName);
Mi pregunta es, ¿cómo puedo pasar DataValueField y DataTextField fuertemente tipeado como un argumento para poblar DataTextField ?
Si solo está tratando de usar cadenas de propiedades, puede cambiar el parámetro a Expression<Func<T, string>> y luego extraer los nombres de las propiedades implicadas; necesitará diseccionar Expression<TDelegate> para obtener ... es de esperar que el Body sea una MemberExpression represente un acceso a la propiedad. Si tiene más de uno ( school.address.FirstLine ), la expresión de destino del acceso de un miembro será otra, etc.
A partir de eso, puede construir una cadena para usar en DataValueField (y DataTextField ). Por supuesto, la persona que llama aún puede atornillarlo:
myDropDownList.populateDropDownList(states,
school => school.stateCode.GetHashCode().ToString(),
school => school.stateName);
... pero puedes detectarlo y lanzar una excepción, y todavía eres resistente a los refactores para las buenas personas que llaman.
Basado en la respuesta de Jon y en esta publicación, me dio una idea. Pasé DataValueField y DataTextField como Expression<Func<TObject, TProperty>> a mi método de extensión. MemberInfo un método que acepta esa expresión y devuelve el MemberInfo para esa propiedad. Entonces todo lo que tengo que llamar es .Name y tengo mi string .
Oh, y cambié el nombre del método de extensión para populate , era feo.
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.");
}
Llamado así ...
myDropDownList.populate(states,
school => school.stateCode,
school => school.stateName);