I have a method which takes in a constructor arguments as
Expression<func<T>>
thus declared as
object[] _constructorArgs = () => new MyClass("StringParam", 56, "ThirdParam");
I would instantiate this object as;
Activator.CreateInstance(typeof(MyClass), _constructorArgs);
Which works fine, but it's a bit slow.
Is there a way I can gather the types Constructor based on the contents of _constructorArgs so I would be able to call
ConstructorInfo.Invoke(_constructorArgs);
?
I know the Invoke is possible this way, it's just about finding the correct constructor based on the parameters in _constructorArgs.
Edit - For clarity
Apologies, I was very tired when I first asked this and should have given it more thought.
What I am doing is the following;
public object Create<T>(Expression<Func<T>> constructor)
{
//I didn't include this step in the original code
var constructorArguments =
(((NewExpression)constructor.Body).Arguments.Select(
argument => Expression.Lambda(argument).Compile().DynamicInvoke())).ToArray();
object[] _args = constructorArguments;
return Activator.CreateInstance(typeof(T), _args);
}
However, if I do the following instead;
ConstructorInfo c = type.GetConstructors().FirstOrDefault();
//Get the types constructor
return c.Invoke(_args);
I get better performance, I'm talking the first taking about 2800 milliseconds over a million iterations, using Invoke bringing that down to about 1000 milliseconds, thus 2.8 times faster.
This will work great if the first constructor always matches the arguments given, but this won't always be the case.
I want to know how I can get the correct ConstructorInfo based on arguments given.
If a million new objects per second isn't fast enough for you, you're going to have to go deeper. You need to start caching things. The simplest thing to cache is the constructor itself, so that you don't have to search for the correct constructor all the time. However...
Why are you doing this? Why don't you simply call the lambda outright? You've got all the code to instantiate the class, and then you throw it away and use Activator.CreateInstance? Why? Even if you do that, you don't need to search for the constructor - NewExpression.Constructor has the ConstructorInfo you need. Just do
((NewExpression)constructor.Body).Constructor.Invoke(_args)
and you're done, no searching needed. All the metadata is already there in the expression tree.
Please explain why you can't simply do return constructor(); (with caching if possible / needed - it's handy to pass things as lambda parameters, since you can then easily cache the method itself).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With