2012-07-26 16 views
5

Antecedentes:¿Cómo puedo simplificar la invocación del método de extensión Linq utilizando la reflexión?

I tiene un servicio web que devuelve las filas en una tabla (nombre de la tabla suministrado como parámetro) con Ids mayor que un cierto Id (también suministrado como parámetro). Estamos asumiendo que los Id. Son secuenciales.

estoy utilizando LINQ to SQL para la interacción de bases de datos, así que quiero volver las nuevas filas como:

List<WhateverObject> 

Debido a que sólo conocemos el nombre de la tabla en tiempo de ejecución, no puedo usar LINQ de una manera normal que ha hecho las cosas mucho más complejas.

Pregunta:

El código está por debajo (y funciona). ¿Cómo puedo simplificarlo? Parece demasiado complejo.

private object GetUpdateList(string tableName, int Id, DataClassesDataContext db) 
{ 
    PropertyInfo pi = db.GetType().GetProperty(tableName); 

    var table = pi.GetValue(db, null); 

    // Get type of object within the table. 
    Type genericType = table.GetType().GetGenericArguments()[0]; 

    // The Where method lives on the Enumerable type in System.Linq 
    var whereMethods = typeof(System.Linq.Enumerable) 
     .GetMethods(BindingFlags.Static | BindingFlags.Public) 
     .Where(mi => mi.Name == "Where"); 

    // There are actually 2 where methods - we want the one with 2 parameters 
    MethodInfo whereMethod = null; 
    foreach (var methodInfo in whereMethods) 
    { 
     var paramType = methodInfo.GetParameters()[1].ParameterType; 
     if (paramType.GetGenericArguments().Count() == 2) 
     { 
      // we are looking for Func<TSource, bool>, the other has 3 
      whereMethod = methodInfo; 
      break; 
     } 
    } 

    Func<object, bool> IdEquals = BuildEqFuncFor("Id", Id); 

    whereMethod = whereMethod.MakeGenericMethod(genericType); 
    var result = whereMethod.Invoke(table, new object[] { table, IdEquals }); 

    MethodInfo toListMethod = typeof(System.Linq.Enumerable).GetMethod("ToList").MakeGenericMethod(genericType); 
    return toListMethod.Invoke(result, new object[] { result }); 
} 

// Build lambda expression for use in Linq 
private static Func<object, bool> BuildEqFuncFor(string prop, object val) 
{ 
    // We know we are comparing integers here so cast them. 
    // There is probably a more general solution. 
    return t => (int)t.GetType().InvokeMember(prop, BindingFlags.GetProperty, null, t, null) > (int)val; 
} 

para llegar a esta solución que he tenido que hacer referencia a las siguientes preguntas:

+0

no arrojar fuera de su pregunta, pero ¿estás en una situación en la que es imposible refactorizar? Parece mucho trabajo para algo tan simple. ¿Necesita ser tan genérico? –

+0

¿Qué sugerirías? –

+0

¿Solo tienes que escribir fuertemente? Pase el nombre de la tabla y la identificación. Selecciónelo de la base de datos y devuelva las filas solicitadas. Devuelve un 'IEnumerable ' y llámalo un día. –

Respuesta

4

intentar algo como esto:

private IList GetUpdateList(string tableName, int id, DataClassesDataContext db) 
{ 
    System.Reflection.PropertyInfo pi = db.GetType().GetProperty(tableName); 

    var table = pi.GetValue(db, null); 

    // Get type of object within the table. 
    Type genericType = table.GetType().GetGenericArguments()[0]; 

    var param = Expression.Parameter(genericType, "x"); 
    var predicateExpr = Expression.Lambda(
     Expression.GreaterThan(
      Expression.Property(param, "Id"), 
      Expression.Constant(id)), 
     param); 

    return this 
     .GetType() 
     .GetMethod("GetUpdateListGeneric") 
     .MakeGenericMethod(genericType) 
     .Invoke(this, new[] { table, predicateExpr }) as IList; 
} 

private IList<T> GetUpdateListGeneric<T>(
    Table<T> table, 
    Expression<Func<T, bool>> predicate) where T : class 
{ 
    return table.Where(predicate).ToList(); 
} 
+0

¡Impresionante! Solo tuve que editar algunas cosas (tipo de retorno) y extraer Expression.Parameter en una variable primero y funciona. –

+0

Me alegro de que haya ayudado, y gracias por las correcciones. – Jacob

Cuestiones relacionadas