I need an efficient way for summing arbitrary properties in two objects of the same type.
I have a class with a large number of properties of different numerical types:
public class MyClass
{
public int Field1 { get; set; }
public long Field2 { get; set; }
public float Field3 { get; set; }
public double Field4 { get; set; }
//...
public uint Field100 { get; set; }
}
At runtime, I allow users to select an arbitrary subset of those fields:
List<PropertyInfo> props = new List<PropertyInfo>();//Field1, Field5, Field99 etc...
I then need to iterate over all selected properties on two objects, sum them, and assign back to the first object:
MyClass mc1 = new MyClass();
MyClass mc2 = new MyClass();
SumProps(mc1, mc2, props);
Which for the example above using fields 1, 5 and 99, would have the effect of doing:
mc1.Field1 += mc2.Field1;
mc1.Field5 += mc2.Field5;
mc1.Field99 += mc2.Field99;
I am currently using reflection with PropertyInfo.GetValue()/SetValue() and manually casting to the appropriate type. This is far too slow since this is a performance critical part of the code that will get called billions of times.
So I need a way of generating an Expression Lambda which will generate the code for summing all requested fields, using the appropriate types. I will then call that lambda like:
MySumPropsLambda(c1, c2);
From what I've researched it will involve BlockExpression and Expression.AddAssign but I can't quite wrap my head around how to actually accomplish it.
I am using Visual Studio 2013 with .NET 4.5.1
Edit: Thanks to Akash Kava below, I've made a slight modification and am using this solution:
public static Action<T, T> MakePropertySummationAction<T>(PropertyInfo[] props)
{
var mc1 = Expression.Parameter(typeof(T));
var mc2 = Expression.Parameter(typeof(T));
var exps = new List<Expression>();
foreach (var pi in props)
{
var p1 = Expression.Property(mc1, pi.Name);
var p2 = Expression.Property(mc2, pi.Name);
exps.Add(Expression.AddAssign(p1, p2));
}
var blockExpr = Expression.Block(exps);
return Expression.Lambda<Action<T, T>>(blockExpr, mc1, mc2).Compile();
}
Printing the block expression strings proves it's generated the desired code:
(Param_0.Field1 += Param_1.Field1)
(Param_0.Field2 += Param_1.Field2)
(Param_0.Field3 += Param_1.Field3)
(Param_0.Field4 += Param_1.Field4)
Performance for doing one million summations in milliseconds:
Direct took 4.8ms
Compiled lambda took 177.5ms
Reflection took 5376.7ms
Working fiddle
https://dotnetfiddle.net/xPrXXG
mc1.Field1 += mc2.Field2;
Lambda Expression equivalent is....
Action<MyClass,MyClass> CreateMethod(string propertyName){
var mc1 = Expression.Parameter(typeof(MyClass));
var mc2 = Expression.Parameter(typeof(MyClass));
var p1 = Expression.Property(mc1, propertyName);
var p2 = Expression.Property(mc2, propertyName);
var assign = Expression.AddAssign(p1,p2);
return Expression.Lambda<Action<MyClass,MyClass>>
(assign,mc1,mc2).Compile();
}
You can call as...
var addAssign1 = CreateMethod("Field1");
// equivalent to mc1.Field1 += mc2.Field1;
addAssign1(mc1,mc2);
What you're looking for is operator overloading:
Example, say you have T a, and T b,
you could do:
public class T{
public int Field1{get;set;}
public static T operator +(T c1, T c2)
{
return new T{Field1=c1.Field1+c2.Field1;}
}
}
and then you can do:
T a,b; //initilaize here
T c= a+b;
To get a new compiled value as the sum of a and b
Edit : Formatting is awful
Related
Assuming I have an object class MyObject with the following properties:
class MyObject {
public int MyProperty1 { get; set; }
public int MyProperty2 { get; set; }
public int MyProperty3 { get; set; }
}
And I have an array of MyObject[] with the following elements:
MyObject[] myObjects => new MyObject[] { myObject1, myObject2, myObject3 };
How do I create a new instance myObject such that its MyProperty1, MyProperty2, and MyProperty3 are the sums of the respective properties for every such object in the array?
Currently, my implementation is as follows
MyObject MyObjectSummed => new MyObject()
{
MyProperty1 = myObjects.Sum(x => x.MyProperty1);
MyProperty2 = myObjects.Sum(x => x.MyProperty2);
MyProperty3 = myObjects.Sum(x => x.MyProperty3);
}
but I vaguely remember seeing a more efficient way of doing this using LINQ, using a single line of code.
Is this possible and can someone please point me in the right direction?
Thanks!
You need to update three properties, so having "one-liner" will make code very unreadable.
If asking about different LINQ approach instead of summarising three values, then Aggregate is your choice, check #Andy's answer.
If you wrap logic with the method then you can use any amount of lines inside the implementation, but keep it one-liner for the consumers.
Alternative approach can be an extension method for enumerable
public static MyObject CalculateSum(this IEnumerable<MyObject> objects)
{
var total = new MyObject();
foreach (var obj in objects)
{
total.MyProperty1 += obj.MyProperty1;
total.MyProperty2 += obj.MyProperty2;
total.MyProperty3 += obj.MyProperty3;
}
return total;
}
Usage is "one-liner" :)
var objects = new MyObject[] { myObject1, myObject2, myObject3 };
var sum = objects.CalculateSum();
Notice that all LINQ methods are extension methods, so you kinda using your own domain specific LINQ "one-liner" ;)
So if you do not want to mutate the original array, this is what you can do:
var result = myObjects.Aggregate(new MyObject(), (accumulate, current) => {
accumulate.MyProperty1 += current.MyProperty1;
accumulate.MyProperty2 += current.MyProperty2;
accumulate.MyProperty3 += current.MyProperty3;
return accumulate;
});
If you do not care you can just do this:
By doing this way you are mutating the first element within the array.
var result = myObjects.Aggregate((accumulate, current) => {
accumulate.MyProperty1 += current.MyProperty1;
accumulate.MyProperty2 += current.MyProperty2;
accumulate.MyProperty3 += current.MyProperty3;
return accumulate;
});
If performance is not an issue, you can use reflections. Then you can add and remove integer properties to your object without having to modify the code of adding. If you convert the return value of GetProperties() to a list, you can use the ForEach() method of List<T>, which even reduces your line count further.
MyObject myObjectSummed = new MyObject();
foreach(var prop in myObjectSummed.GetType().GetProperties().Where(p => p.PropertyType == typeof(int)))
{
prop.SetValue(myObjectSummed, myObjects.Sum(x => (int)prop.GetValue(x)));
}
But i recommend Fabio's answer: From my point of view, it's clearest way to write this logic. Having as few lines of code as possible is not always the best approach.
I am wondering about the best approach to the below
I have a .NET Web application and I am changing the ORM provider I am using. To do this I have created a new solution and removed the previous ORM and implemented my new one. As there are lots of existing screens that work with the previous ORM I want to make sure that the same object is returned by both ORMS. As these are in two separate VS slns is there a simple way I can compare the complex objects that all the same properties have been loaded on to the object graph. I could set a breakpoint and compare them manually but I don't really want to do this?
If this is for testing purposes, you can use FluentAssertions to check this.
The following code declares two unrelated types, ClassA and ClassB which contain two nested classes both called A and B but of different types.
Therefore the containing classes and the nested classes are of unrelated types, but the names of the members are the same, and for the nested classes the types of the properties are the same.
You can use FluentAssertions to test if the two instances classA and classB are equivalent - even though they are of different types - as follows:
using System;
using FluentAssertions;
namespace Demo
{
class ClassA
{
public NestedClassA A;
public NestedClassB B;
}
class NestedClassA
{
public string S;
public int I;
}
class NestedClassB
{
public char C;
public double D;
}
class ClassB
{
public NestedClassC A;
public NestedClassD B;
}
class NestedClassC
{
public string S;
public int I;
}
class NestedClassD
{
public char C;
public double D;
}
internal class Program
{
private static void Main()
{
var nestedA = new NestedClassA {I = 1, S = "1"};
var nestedB = new NestedClassB {C = '1', D = 1};
var nestedC = new NestedClassC { I = 1, S = "1" };
var nestedD = new NestedClassD { C = '1', D = 1 };
var classA = new ClassA {A = nestedA, B = nestedB};
var classB = new ClassB {A = nestedC, B = nestedD};
classA.ShouldBeEquivalentTo(classB); // Passes
classB.ShouldBeEquivalentTo(classA); // Passes
classB.B.D = 2; // Now the two objects do not contain equivalent data.
classA.ShouldBeEquivalentTo(classB); // Fails.
}
}
}
So I am guessing it is not as simple as to implement the IEquatable interface and directly compare your instances using this. You have to be aware that implementing proper comparing methods will be the fastest way.
But there are slower, more flexible ways. I think what you want to do is:
Compare two objects of unknown types
Check if they contain class variables with the same name
Check if the class variables have matching types
Check if the values in the variables are the same
There is only one way to do that. And it is to throw System.Reflection at the problem. Mind that this solution will be considerably slower then all solutions that work with known types.
So you need your ComplexEquals function.
public static bool ComplexEquals(object obj1, object obj2)
{
if (obj1 == null && obj2 == null) return true;
if (obj1 == null || obj2 == null) return false;
var obj1Class = obj1.GetType();
var obj2Class = obj2.GetType();
/* Get the instance fields (all of them) of both classes. */
var obj1Fields = obj1Class.GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
var obj2Fields = obj2Class.GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
var checkedFields = new HashSet<String>();
foreach (var obj1Field in obj1Fields)
{
var fieldName = obj1Field.Name;
checkedFields.Add(fieldName);
var obj2Field = obj2Fields.Where(f => f.Name == fieldName).SingleOrDefault();
if (obj2Field == null) return false;
if (obj1Field.FieldType == obj2Field.FieldType && !(obj1Field.GetValue(obj1).Equals(obj2Field.GetValue(obj2)))) return false;
}
if (obj2Fields.Any(f => !checkedFields.Contains(f.Name))) return false;
return true;
}
This is a simple version that relies on the Equals function starting at the first level inside the unknown function. This may be sufficient or not. But I think that is a starting point that can be extended if required.
I am creating a custom reporting tool that allows the user to enter a list of criteria.
public partial class CustomReportCriteria
{
public int Id { get; set; }
public int ReportId { get; set; }
public string Operator { get; set; }
public string CriteriaValue { get; set; }
public string CriteriaType { get; set; }
public string CriteriaField { get; set; }
public string PropertyType { get; set; }
public virtual CustomReport CustomReport { get; set; }
}
I need to utilize these fields to create dynamic queries on my database. For example:
Select BidYear From FWOBid Where BidYear = 2015
// ^ this would look like this instead
Select CriteriaField From PropertyType Where CriteriaField [Operator] CriteriaValue
However, I may not always be querying the same table, and in most cases the query will require joins on other tables.
I already have generic methods for the where clauses:
public static IQueryable<T> Filter<T>(IQueryable<T> query, string propertyName, string propertyValue, string op)
{
PropertyInfo propertyInfo = typeof(T).GetProperty(propertyName);
return Filter<T>(query, propertyInfo, propertyValue, op);
}
public static IQueryable<T> Filter<T>(IQueryable<T> query, PropertyInfo propertyInfo, string propertyValue, string op)
{
ParameterExpression e = Expression.Parameter(typeof(T), "e");
MemberExpression m = Expression.MakeMemberAccess(e, propertyInfo);
UnaryExpression c = GetExpressionByType(propertyValue, propertyInfo.PropertyType);
BinaryExpression b = null;
if (op == "=")
{
b = Expression.Equal(m, c);
}
else if (op == "!=")
{
b = Expression.NotEqual(m, c);
}
else if (op == ">")
{
b = Expression.GreaterThan(m, c);
}
else if (op == "<")
{
b = Expression.LessThan(m, c);
}
Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(b, e);
return query.Where(lambda);
}
The approach I was envisioning was something like this:
foreach (var crit in report.CustomReportCriterias)
{
var objectName = crit.PropertyType;
var value = crit.CriteriaValue;
var type = crit.CriteriaType;
var field = crit.CriteriaField;
var op = crit.Operator;
// how to dynamically get a generic collection ?
var queryable = _context.Set<objectName>();
var results = Filter<objectName>(queryable, field, value, op);
// would then do joins if needed
}
But, I'm struggling with the initial steps of retrieving a queryable from the db based on a string, and then I'm lost as how to join these results after.
Using Entity Framework you can execute a query directly and have the results map to an entity like this.
var results = db.ExecuteStoreQuery<YourEntity>(
"SELECT * FROM YourEntities WHERE SomeColumn = #param1",
param1);
Have a look at https://dynamiclinq.codeplex.com/releases/view/109593. This library extends the Linq library with a System.Linq.Dynamic namespace that provides string-based overloads to common query methods, so you can dynamically build string-based criteria for filtering and grouping. In addition, the one in my link is one better than the version available through NuGet, because it allows you to define the entire query, including the record type to retrieve, in Linq syntax as one string (see the Documentation tab for one example; it uses a static typeof expression to provide a Type to parse the results into, but you can reflectively create generic types with Type.MakeGenericType()).
The problem's going to be getting back to a statically-defined type; once you go dynamic, you tend to have to stay dynamic, using GetProperties() to enumerate data fields and GetValue/SetValue to manipulate them. There are a few tricks, typically requiring the use of a set of concretely-typed overloads that force the runtime to examine the true type of the object, then once the object's passed into one of those overloads you're back in static world again.
class Program
{
static void Main(string[] args)
{
Expression<Func<string[], Poco>> exp = a => new Poco { MyProperty1 = a[0], MyProperty2 = a[1], MyProperty3 = a[2] };
var lambda = exp.Compile();
var output = lambda(new[] {"one", "two", "three"});
Console.WriteLine(output.MyProperty1);
}
}
class Poco
{
public string MyProperty1 { get; set; }
public string MyProperty2 { get; set; }
public string MyProperty3 { get; set; }
}
I'm not interested in the part calling the lambda, thats just for completeness. I get completely lost trying to navigate expression trees, and this might teach me how to fish.
private static Expression<Func<string[], Poco>> CreateExpr()
{
ParameterExpression paramExpr = Expression.Parameter(typeof(string[]), "a");
var newExpr = Expression.New(typeof(Poco));
var memberExprs = Enumerable.Range(0, 3)
.Select(i =>
{
string propertyName = "MyProperty" + (i + 1);
var property = typeof(Poco).GetProperty(propertyName);
Expression.Bind(property, Expression.ArrayIndex(paramExpr, Expression.Constant(i)));
});
var expr = Expression.MemberInit(newExpr, memberExprs);
return Expression.Lambda<Func<string[], Poco>>(expr, paramExpr);
}
I don't have time right now to translate the complete tree, but one thing you can do is compile your code and then use ildasm (or reflector etc) to look at what the compiler's doing. You can't always do exactly the same in your own code, but it gives you an idea of the kind of expressions you'll want. In particular, in this case you'll want:
Expression.Parameter to create the parameter (a)
Expression.New to create the new instance
Expression.Bind to create a property assignment
Expression.MemberInit to assign the properties in the new object
Expression.ArrayIndex for each array access (a[0] etc)
Expression.Constant for the array indexes themselves (0, 1, 2)
Expression.Lambda to create an Expression<TDelegate> for the whole thing
If I get time later on, I'll try to construct a complete working example.
Similar: Convert a string to Linq.Expressions or use a string as Selector?
A similar one of that one: Passing a Linq expression as a string?
Another question with the same answer: How to create dynamic lambda based Linq expression from a string in C#?
Reason for asking something which has so many similar questions:
The accepted answer in those similar questions is unacceptable in that they all reference a library from 4 years ago (granted that it was written by code master Scott Gu) written for an old framework (.net 3.5) , and does not provide anything but a link as an answer.
There is a way to do this in code without including a whole library.
Here is some sample code for this situation:
public static void getDynamic<T>(int startingId) where T : class
{
string classType = typeof(T).ToString();
string classTypeId = classType + "Id";
using (var repo = new Repository<T>())
{
Build<T>(
repo.getList(),
b => b.classTypeId //doesn't compile, this is the heart of the issue
//How can a string be used in this fashion to access a property in b?
)
}
}
public void Build<T>(
List<T> items,
Func<T, int> value) where T : class
{
var Values = new List<Item>();
Values = items.Select(f => new Item()
{
Id = value(f)
}).ToList();
}
public class Item
{
public int Id { get; set; }
}
Note that this is not looking to turn an entire string into an expression such as
query = "x => x.id == somevalue";
But instead is trying to only use the string as the access
query = x => x.STRING;
Here's an expression tree attempt. I still don't know if this would work with Entity framework, but I figure it is worth a try.
Func<T, int> MakeGetter<T>(string propertyName)
{
ParameterExpression input = Expression.Parameter(typeof(T));
var expr = Expression.Property(input, typeof(T).GetProperty(propertyName));
return Expression.Lambda<Func<T, int>>(expr, input).Compile();
}
Call it like this:
Build<T>(repo.getList(), MakeGetter<T>(classTypeId))
If you can use an Expression<Func<T,int>> in place of a just a Func, then just remove the call to Compile (and change the signature of MakeGetter).
Edit:
In the comments, TravisJ asked how he could use it like this: w => "text" + w.classTypeId
There's several ways to do this, but for readability I would recommend introducing a local variable first, like this:
var getId = MakeGetter<T>(classTypeId);
return w => "text" + getId(w);
The main point is that the getter is just a function, and you can use it exactly like you normally would. Read Func<T,int> like this: int DoSomething(T instance)
Here is an extension method for you with my testing code (linqPad):
class test
{
public string sam { get; set; }
public string notsam {get; set; }
}
void Main()
{
var z = new test { sam = "sam", notsam = "alex" };
z.Dump();
z.GetPropertyByString("notsam").Dump();
z.SetPropertyByString("sam","john");
z.Dump();
}
static class Nice
{
public static void SetPropertyByString(this object x, string p,object value)
{
x.GetType().GetProperty(p).SetValue(x,value,null);
}
public static object GetPropertyByString(this object x,string p)
{
return x.GetType().GetProperty(p).GetValue(x,null);
}
}
results:
I haven't tried this, and not sure if it would work, but could you use something like:
b => b.GetType().GetProperty(classTypeId).GetValue(b, null);