获取构造函数匹配参数

时间:2014-03-27 20:38:18

标签: c# .net reflection activator

我有一个方法,它将构造函数参数作为

Expression<func<T>>

因此声明为

object[] _constructorArgs = () => new MyClass("StringParam", 56, "ThirdParam");

我会将此对象实例化为;

Activator.CreateInstance(typeof(MyClass), _constructorArgs);

哪种方法很好,但速度有点慢。

有没有办法可以根据_constructorArgs的内容收集类型构造函数,这样我就可以调用

ConstructorInfo.Invoke(_constructorArgs);

我知道Invoke是可行的,它只是根据_constructorArgs中的参数找到正确的构造函数。

修改 - 为清晰起见

道歉,当我第一次问这个问题时,我感到很累,应该多考虑一下。

我正在做的是以下内容;

    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);
    }

但是,如果我改为做以下事情;

         ConstructorInfo c = type.GetConstructors().FirstOrDefault();

        //Get the types constructor
        return c.Invoke(_args);

我获得了更好的性能,我说的是第一次在一百万次迭代中花费大约2800毫秒,使用Invoke将其降低到大约1000毫秒,因此速度提高了2.8倍。

如果第一个构造函数总是与给定的参数匹配,这将很有用,但这不会总是如此。

我想知道如何根据给定的参数获取正确的ConstructorInfo。

3 个答案:

答案 0 :(得分:1)

引擎盖下的{p> Activator.CreateInstance()调用GetConstructors()并迭代它们以找到匹配的。这可以解释性能上的差异 - 如果你推出自己的实现机会,你最终会得到相同或更差的性能。

您可以通过使用parameterType.IsAssignableFrom(argType)比较类型来简化流程,并返回第一个匹配项 - 您最终可能会使用与Activator.CreateInstance()不同的构造函数,因为它使用最佳匹配,而不是第一场比赛

class DerivedClass : BaseClass { }

class Test
{
    public Test(BaseClass c)
    {
    }

    public Test(DerivedClass c)
    {
    }
}

// Uses the most specific constructor, Test(DerivedClass):
Activator.CreateInstance(typeof(Test), new DerivedClass());

答案 1 :(得分:1)

如果每秒有一百万个新物体对你来说不够快,那么你将不得不走得更远。你需要开始缓存。缓存最简单的事情是构造函数本身,因此您不必一直搜索正确的构造函数。然而...

你为什么要这样做?你为什么不直接打电话给lambda?您已经获得了实例化该类的所有代码,然后将其丢弃并使用Activator.CreateInstance?为什么?即使您这样做,也不需要搜索以获取构造函数 - NewExpression.Constructor具有您需要的ConstructorInfo。只是做

((NewExpression)constructor.Body).Constructor.Invoke(_args) 

你完成了,不需要搜索。所有元数据都已存在于表达式树中。

请解释为什么你不能简单地return constructor();(如果可能/需要缓存) - 将事物作为lambda参数传递是很方便的,因为你可以轻松地缓存方法本身)

答案 2 :(得分:0)

可能会有点迟,但我发现了一个很好的缓存实现,声称比Activator.CreateInstance快70倍;

this.Item = (T)Activator.CreateInstance(typeof(T), new Object[] { x, y }, null); // Classical approach
this.Item = Constructor<Func<int,int,T>>.Ctor(x,y); // Dynamic constructor approach

完整的实施可以在这里找到: http://www.cyberforum.ru/blogs/32756/blog2078.html

相关问题