2011-09-23 13 views
9

Tengo una configuración de trabajo que no está muy tipada y se basa en la reflexión.lambda Expresión como propiedad

tengo una clase, digamos

class Person{ 

    public string FirstName {get ; set;} 
    public string LastName {get; set;} 
    public int Age {get; set;} 
    ... 
    // some more public properties 
} 

y

class CellInfo { 
    public string Title {get; set;} 
    public string FormatString {get; set;} 
} 

y tengo un diccionario como este

Dictionary<string, CellInfo> fields = new Dictionary<string, CellInfo>(); 
fields.Add("FirstName", new CellInfo {Title = "First Name", FormatString = "Foo"}); 
fields.Add("LastName", new CellInfo {Title = "Last Name", FormatString = "Bar"}); 

Es un diccionario sencillo con propiedad nombres y algo de información acerca ellos. que pase el diccionario a otro módulo que procesa casos persona y hago

Dictionary<string, CellInfo> fields = SomeMethodToGetDictionary(); 
foreach(Person p in someCollection) 
{ 
    foreach(var field in fields) 
    { 
     object cellValue = type(Person).GetProperty(field.Key).GetValue(p, null); 
     // use cellValue and info on field from field.Value somewhere. 
     ... 
    } 
} 

Este método de pasar la cadena de nombre de campo y utilizando la reflexión funciona, pero me preguntaba si hay un método de establecimiento inflexible de hacer esta.

Lo que tenía en mente era tener una propiedad que almacena una expresión LINQ, algo como esto

fields.Add("FirstName", new CellInfo 
        { 
         Title = "First Name", 
         FormatString = "Foo", 
         EvalExpression = p => p.FirstName 
        }); 

y durante el uso, de alguna manera utilizar el EvalExpression en un objeto persona y obtener el valor de la propiedad. No tengo ni idea de dónde comenzar ni cómo sería la sintaxis para tener una propiedad como esta que sea evaluable. Soy nuevo para delegados de función y árboles de expresión que ni siquiera conozco las palabras clave adecuadas para buscar. Espero que mi descripción sea clara; si no, avíseme y detallaré según sea necesario. Cualquier ayuda sería muy apreciada.

Respuesta

1

Usted puede intentar algo como esto para no tener que codificar los nombres de propiedades como cadenas si esto es lo que quiere decir diciendo establecimiento inflexible:

class CellInfo<T> 
{ 
    public string Title { get; set; } 
    public string FormatString { get; set; } 
    public Func<T, object> Selector { get; set; } 
} 

Dictionary<string, CellInfo<Person>> dict = new Dictionary<string, CellInfo<Person>>(); 

dict.Add("LastName", new CellInfo<Person> { Selector = p => p.LastName }); 
dict.Add("Age", new CellInfo<Person> { Selector = p => p.Age }); 

foreach (Person p in someCollection) 
{ 
    foreach (var cellInfo in dict) 
    { 
     object value = cellInfo.Value.Selector(p); 
    } 
} 
-1

(Su pregunta es clara, pero larga. Recorte el material inicial.)

Esta es la forma en ASP.NET MVC utiliza expresiones de reflexión y lambda para la creación de nombres de campo en las entradas HTML, etc. Por lo que podría tener una mira el código fuente para ese asunto.

En términos simples, debe convertir su expresión a la expresión Miembro y obtener el nombre. Fácil:

MemberExpression memberExpression = EvalExpression.Body as MemberExpression; 
if (memberExpression == null) 
    throw new InvalidOperationException("Not a memberExpression"); 

if (!(memberExpression.Member is PropertyInfo)) 
    throw new InvalidOperationException("Not a property"); 

return memberExpression.Member.Name; // returns FirstName 
+0

a alguien le interesa c ¿por qué downvote? – Aliostad

+0

Podría ser el comando (en oposición a la solicitud) en la primera línea. – MikeKulls

0

Creo que un delegado es lo que necesita. Algo como esto:

public delegate string EvalExpressionDelegate (Person); 

class CellInfo 
{ 
    public string Title {get; set;} 
    public string FormatString {get; set;} 
    public EvalExpressionDelegate EvalExpression = null; 
} 

fields.Add("FirstName", new CellInfo 
        { 
         Title = "First Name", 
         FormatString = "Foo", 
         EvalExpression = p => p.FirstName 
        }); 
+0

+1 Buena información. Supongo que 'Func ' es una abreviatura del delegado que tienes y alguien no se dio cuenta y te dio un voto negativo. –

+0

@ProfessorChaos Creo que la votación negativa se debe probablemente a que escribir al delegado se considera la forma antigua de hacerlo, aunque puede tener sus ventajas, como nombrar los parámetros. – MikeKulls

2

Usar un delegado :

class CellInfo { 
    public string Title {get; set; } 
    public string FormatString {get; set; } 
    public Func<Person, object> EvalExpression { get; set; } 
} 

Entonces su entrada lambda va a funcionar ...

Cuestiones relacionadas