12

I read type from loaded assemblies for example:

var someType = loadedAssemblies
            .Where(a => a != null && a.FullName.StartsWith("MY."))
            .SelectMany(a => a.GetTypes())
            .Distinct()
            .ToArray()[0];

If counstructor has parameters, i can read them:

ParameterInfo[] parameters = classType.GetConstructors()[0].GetParameters();

I would like to call constructor with default parameter values or if parameter is enum, with first enum value. If there is only one parameter and it is enum, it works like this:

object curObject = Activator.CreateInstance(classType, new object[] { parameters[0].ParameterType.GetEnumValues().GetValue(0) });

How can I do this when there are more parameters? I need to create object to read the property:

var propertyInfo = someType.GetProperty("EntityType");
string entityType = propertyInfo.GetValue(curObject, null).ToString();

2 Answers 2

11

Well, you can create your own Factory, and write a method, that checks constructors for the type and runs first parameterized ctor with its default values:

public static class MyFactory
{
    public static T MyCreateInstance<T>()
        where T : class
    {
        return (T) MyCreateInstance(typeof (T));
    }

    public static object MyCreateInstance(Type type)
    {
        var parametrizedCtor = type
            .GetConstructors()
            .FirstOrDefault(c => c.GetParameters().Length > 0);

        return parametrizedCtor != null
            ? parametrizedCtor.Invoke
                (parametrizedCtor.GetParameters()
                    .Select(p =>
                        p.HasDefaultValue? p.DefaultValue :
                        p.ParameterType.IsValueType && Nullable.GetUnderlyingType(p.ParameterType) == null
                            ? Activator.CreateInstance(p.ParameterType)
                            : null
                    ).ToArray()
                )
            : Activator.CreateInstance(type);
    }
}

And then use this method:

var classType = loadedAssemblies
            .Where(a => a != null && a.FullName.StartsWith("MY."))
            .SelectMany(a => a.GetTypes())
            .Distinct()
            .ToArray()[0];

var curObject = MyFactory.MyCreateInstance(classType);

// This will return an array of values

object[] values = classType
                 .GetFields()
                 .Select(f => f.GetValue(curObject))
                 .ToArray();

P.S. Here is a DotNet fiddle example.

Update:

The code is changed according to scenario you work with. Now we have two methods, one returns object, and another one that can convert it to type T.

I've also updated the DotnetFiddle, please check it.

Sign up to request clarification or add additional context in comments.

3 Comments

Hi Fabjan, thanks for this solution. There is one problem. I have only classType, which i read at runtime. I don't know for the object(class) name at compile time. Your code: var curObject = MyFactory.MyCreateInstance<object>(classType); doesn't work with object keyword.
I've updated my answer as well as code example on DotNetfiddle
Thank you, it works perfect. Do you know the difference between constructor.Invoke vs Activator.CreateInstance?
2

You can make a helper method to get default value of a type:

private static object GetDefaultValue(Type type)
{
    if (type.IsEnum) return type.GetEnumValues().GetValue(0);
    if (type.IsValueType) return Activator.CreateInstance(type);
    return null;
}

Then, you can get default values of the parameters:

var parameters = constructor.GetParameters()
                            .Select(p => GetDefaultValue(p.ParameterType))
                            .ToArray();

And invoke the ConstructorInfo to get the instance:

var obj = constructor.Invoke(parameters);

If the constructor's parameters have default values and you want to use them, you can do something like this:

var parameters = constructor
    .GetParameters()
    .Select(p => p.HasDefaultValue ? p.RawDefaultValue : GetDefaultValue(p.ParameterType))
    .ToArray();

2 Comments

Arturo, what is the difference of constructor.Invoke vs Activator.CreateInstance? Can you do the same with Activator.CreateInstance?
@Simon: Constructor.Invoke directly invoke that constructor. Activator.CreateInstance creates an instance finding the constructor that best matches the specified parameters.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.