Tengo un flujo de miles de datos que necesito transformar y agregar a una lista. La transformación ocurre a través de la reflexión similar a la siguiente
_myObservable.Subscribe(d => { PropertyInfo[] props = d.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); var propValDict = props.ToDictionary(prop => prop.Name, prop => prop.GetValue(d, null)); myList.Add(propValDict); }); // Datatype of d is determined during runtime and there are only 8 possibilities of the typePero este enfoque está ralentizando el rendimiento y espero que el uso de la reflexión sea la razón. Estoy pensando en mejorar el rendimiento por otros medios.
Las sugerencias parecen apuntar al uso de árboles de expresión, crear lambda compilada (Func<object,Dictionary<string, object>>) y almacenarla en un diccionario de búsqueda de antemano.
//Foreach possibleType in PossibleTypes, Do below PropertyInfo[] props = possibleType.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); var rootParam = Expression.Parameter(typeof(object), "d"); var param = Expression.Parameter(typeof(PropertyInfo), "prop"); var propertyFirst = Expression.Property(param, "Name"); var param2 = Expression.Parameter(typeof(PropertyInfo), "prop"); var callMethod = Expression.Call(param2, typeof(PropertyInfo).GetMethod(nameof(PropertyInfo.GetValue), new Type[] { typeof(object) }), rootParam); var pro = Expression.Parameter(typeof(Array), "props"); var toDict = Expression.Invoke(pro, propertyFirst, callMethod); var lambda = Expression.Lambda<Func<object, Dictionary<string, object>>>(toDict, rootParam); var compiled = lambda.Compile();Tengo problemas para invocar ToDictionary de la clase Enumerable Hay algo que me falta con este enfoque o ¿Esto realmente mejorará el rendimiento?
Por favor ayuda...
Al pensar con expresiones, siempre debe averiguar cómo se vería el código C# equivalente. En este caso, el código C# equivalente no estaría recorriendo una colección de PropertyInfo , sino que probablemente se vería así:
public static Func<object, Dictionary<string, object>> CreateConvertToPropertyDict<T>() { return input => { var d = (T)input; return new Dictionary<string, object>()) { { "Foo", d.Foo }, { "Bar", d.Bar }, }; }; } myList.Add(propValDict);Muévase hacia los lados en la tierra de las expresiones, y terminará con algo como:
public static Func<object, Dictionary<string, object>> CreatePropertyDict(Type type) { // Consider caching these in a static field, since they're constant var dictType = typeof(Dictionary<string, object>); var dictCtor = dictType.GetConstructor(new[] { typeof(int) }); var dictAddMethod = dictType.GetMethod("Add"); var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); var blockExpressions = new List<Expression>(); // 'object input' is our input parameter var inputParameter = Expression.Parameter(typeof(object), "input"); // MyType d; var dVariable = Expression.Variable(type, "d"); // d = (MyType)inputObject; blockExpressions.Add(Expression.Assign(dVariable, Expression.Convert(inputParameter, type))); // Dictionary<string, object> dict; var dictVariable = Expression.Variable(dictType, "dict"); // dict = new Dictionary<string, object>(3) (or however many properties there are) blockExpressions.Add(Expression.Assign(dictVariable, Expression.New(dictCtor, Expression.Constant(properties.Length)))); foreach (var property in properties) { var propertyAccess = Expression.Property(dVariable, property); // dict.Add("Foo", (object)d.Foo) blockExpressions.Add(Expression.Call( dictVariable, dictAddMethod, Expression.Constant(property.Name), Expression.Convert(propertyAccess, typeof(object)))); }; // The final statement in a block is the return value blockExpressions.Add(dictVariable); var block = Expression.Block(new[] { dVariable, dictVariable }, blockExpressions); return Expression.Lambda<Func<object, Dictionary<string, object>>>(block, inputParameter).Compile(); }Con el caso de prueba simple:
public static void Main() { var test = new Test() { Foo = "woop", Bar = 3 }; var expr = CreatePropertyDict(typeof(Test)); expr(test).Dump(); }Hay varios usos más avanzados de Expression aquí, y no voy a entrar en los detalles de cada uno. Mire los documentos y juegue con los tipos de expresiones que genera el compilador de C# para diferentes bits de código de C#.