I am working on an automation for instantiating classes dynamically.
I decided to write an expression tree that would generate a Func
, that could instantiate my class for me. However, I am noticing 3x slower performance of my Func
as opposed to simply using new
.
From what I know about expression trees and invoking functions, the performance difference should be almost non-existant (maybe 20-30%, but nowhere near 3 times slower)
First off, here is the expression that I am building
public Expression<Func<A1, T>> BuildLambda<T, A1>(string param1Name)
{
var createdType = typeof(T);
var param = Expression.Parameter(typeof(A1), param1Name);
var ctor = Expression.New(createdType);
var prop = createdType.GetProperty(param1Name);
var displayValueAssignment = Expression.Bind(prop, param);
var memberInit = Expression.MemberInit(ctor, displayValueAssignment);
return
Expression.Lambda<Func<A1, T>>(memberInit, param);
}
I then proceed to compile it like so (I do this only once)
var c1 = mapper.BuildLambda<Class1, int>("Id").Compile();
And then I invoke my Func like so
var result = c1.Invoke(5);
When I put this last part in a loop and compare it to something like
var result = new Class1() { Id = 5 };
I did a couple of tests, comparing the performance in both, and this is what I ended up with:
100,000 Iterations - new: 0ms. | Func 2ms.
600,000 Iterations - new: 5ms. | Func 14ms.
3,100,000 Iterations - new: 24ms. | Func 74ms.
15,600,000 Iterations - new: 118ms. | Func 378ms.
78,100,000 Iterations - new: 597ms. | Func 1767ms.
As you can see my Func.Invoke()
is roughly 2.5 - 3 times slower than instantiating using new
.
Does anyone have any tips on how I might improve this? (I don't mind using pure reflection as I manage to get better performance)
*For anyone who wants to test this here is a pastebin of my setup: https://pastebin.com/yvMLqZ2t
ExpressionParam
class and the namespace declaration, it's only about 60 lines... – Speciej => new Class1 { Id = j }
, gets somewhere between the two. – Specie[assembly: AllowPartiallyTrustedCallers]
to your code, the results of the two variants are pretty much the same (at most 1.5 times slower expression calls on my machine). Also, there is a link in that answer to another question with the same answer. I'm not sure why, though, so if someone can go deeper than 'this seems to be a bit of a bug', I'd be grateful too... – GunningSecurityRulesAttribute
withSecurityRuleSet.Level1
. .Net Core generated assembly does not have this attribute, and by reading on this attribute and based on answer to first question recommended by @IvanStoev, this might be the culprit. Assemblies without this attribute specifically applied getSecurityRuleSet.Level2
value on framework 4.0 and higher. – Wally