Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reflection - Call constructor with parameters

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();
like image 888
Simon Avatar asked Dec 01 '16 15:12

Simon


1 Answers

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.

like image 93
Fabjan Avatar answered Oct 22 '22 02:10

Fabjan