“CLR detected an Invalid Program” when compiling a constructor for List<T>

142 views Asked by At

I'm running into a strange problem when compiling a lambda expression for a parameterless constructor into a delegate. It works for almost all types that I have tried. Only the List<> is producing a “CLR detected an Invalid Program”. A Collection<> or an inherited class from List<> would not present the problem.

/// <summary>
/// Delegate for activating instances of objects.
/// </summary>
/// <param name="args">Arguments of the construtor.</param>
/// <returns>A new instance of the object.</returns>
public delegate Object InstanceActivator(params object[] args);

/// <summary>
/// Compiles an instance activator.
/// </summary>
/// <param name="objectType">Type of the object to be created.</param>
/// <param name="definition">Constructor parameters as string.</param>
/// <returns>An compiled instance activator to be used for activating new instances of the object.</returns>
public static InstanceActivator CompileDefaultConstructorToInstanceActivator(Type objectType)
{
    ConstructorInfo foundConstructor = default(ConstructorInfo);

    foreach (ConstructorInfo constructorInfo in objectType.GetTypeInfo().DeclaredConstructors)
    {
        if(constructorInfo.GetParameters().Length == 0)
        {
            foundConstructor = constructorInfo;
        }
    }

    ParameterInfo[] paramsInfo = foundConstructor.GetParameters();

    ParameterExpression parameter = Expression.Parameter(typeof(object[]), "args");

    Expression[] argumentExpressions = new Expression[paramsInfo.Length];

    NewExpression newExpression = Expression.New(foundConstructor, argumentExpressions);
    LambdaExpression lambda = Expression.Lambda(typeof(InstanceActivator), newExpression, parameter);

    return (InstanceActivator)lambda.Compile();
}

So when I call this method the following way it works great:

    [TestMethod]
    public void CreateGenericCollectionOfString()
    {
        Object activatedObject = Sandbox.Functions.Activator.CompileDefaultConstructorToInstanceActivator(typeof(Collection<String>))();

        Assert.IsNotNull(activatedObject);
        Assert.IsInstanceOfType(activatedObject, typeof(Collection<String>));
    }

But the following test would throw an error:

    [TestMethod]
    public void CreateGenericListOfString()
    {
        Object activatedObject = Sandbox.Functions.Activator.CompileDefaultConstructorToInstanceActivator(typeof(List<String>))();

        Assert.IsNotNull(activatedObject);
        Assert.IsInstanceOfType(activatedObject, typeof(List<String>));
    }

Hope somebody can explain me the reason for this.

I have uploaded the sample project with unit tests reproducing the problem to GitHub.

https://github.com/teoturner/Sandbox/blob/master/Code/Functions/Activator.cs https://github.com/teoturner/Sandbox/blob/master/Code/Tests/ActivatorTests.cs

1

There are 1 answers

0
xanatos On BEST ANSWER

The DeclaredConstructors property will return even the static constructor of List<>. You clearly can't invoke it.

Use:

ConstructorInfo foundConstructor = objectType.GetTypeInfo().GetConstructor(Type.EmptyTypes);