【转载】反射之实例创建ConstructorInfo.Invoke 对比 Activator.CreateInstance

About a year ago I blogged about different methods of object instantiation and that compiled lambda expressions should be preferred in case same type is instantiated frequently and instantiation performance is critical. However, on many occasions dealing with expression compilation is not worth it, and creating an instance using reflection is simple and usually good enough. Then Activator.CreateInstance seems to be a default choice for such operations. What can be simpler than this call?

1
var instance = Activator.CreateInstance<SomeType>();

The problem with this approach is its false sense of simplicity: it gives an impression that the instance will be created without any additional information, for example initialization parameters.

To prove how misleading such simplicity can be you just need to try creating an instance of a string:

1
var instance = Activator.CreateInstance<string>();

The line above causes MissingMethodException with message “No parameterless constructor defined for this object”. And of course, System.String does not have a default constructor.

So what to do? We can of course say that if a class does not have default constructor, then instantiating it in such way is a bad idea, and those classes are just not intended to be used with code trying to create class instances in such manner. However, I bet that more often than not the semantics behind the code “Activator.CreateInstance<T>” is “give me some instance of T, I don’t care about how you create it”. Under such conditions invoking an arbitrary class constructor is preferred over dealing with MissingMethodException. So why not using ConstructorInfo.Invoke then?

Of course, once you settle for ConstructorInfo, you have to decide what constructor overload to use. But this is not really different from choosing parameterless overload of Activator.CreateInstance. In many cases you don’t choose default constructor because this the state of the object you need – you choose it because you don’t care about the state and thus would like to run the simplest form of creation. Applying the same logic to classes without default constructor we can choose a constructor overload with fewest number of parameters:

1
2
3
4
var constructor = typeof(T).GetConstructors().OrderBy(c => c.GetParameters().Length).FirstOrDefault();
if (constructor == null)
    throw new MissingMethodException("No public constructor defined for this object");
var instance = constructor.Invoke(new object[constructor.GetParameters().Length]);

One area when this approach can be useful is if there is a need to create an instance of an anonymous type (I know it’s a very special need – why on earth will you want to create an instance of an anonymous type? – but I’ve come across a situation):

1
2
3
var o = new { A = "a", B = 1 };
var constructor = o.GetType().GetConstructors()[0];
var instance = constructor.Invoke(new object[constructor.GetParameters().Length]);

Anonymous types don’t get a parameterless constructor, but there is a constructor with a number of arguments equal to the number of type’s properties. I would however use syntax GetConstructors().OrderBy(c => c.GetParameters().Length).FirstOrDefault() that can be applied in general case.

原文地址:https://www.cnblogs.com/zhxhdean/p/3077332.html