tipados tipado lenguajes fuertemente débilmente dinamico c# lambda strong-typing

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);