C# 反射-使用参数调用构造函数

C# 反射-使用参数调用构造函数,c#,reflection,enums,C#,Reflection,Enums,我从加载的程序集中读取类型,例如: var someType = loadedAssemblies .Where(a => a != null && a.FullName.StartsWith("MY.")) .SelectMany(a => a.GetTypes()) .Distinct() .ToArray()[0]; 如果Constructor有参数,我可以读取它们

我从加载的程序集中读取类型,例如:

var someType = loadedAssemblies
            .Where(a => a != null && a.FullName.StartsWith("MY."))
            .SelectMany(a => a.GetTypes())
            .Distinct()
            .ToArray()[0];
如果Constructor有参数,我可以读取它们:

ParameterInfo[] parameters = classType.GetConstructors()[0].GetParameters();
我希望使用默认参数值调用构造函数,或者如果参数是enum,则使用第一个enum值调用构造函数。 如果只有一个参数且为enum,则其工作原理如下:

object curObject = Activator.CreateInstance(classType, new object[] { parameters[0].ParameterType.GetEnumValues().GetValue(0) });
var parameters = constructor
    .GetParameters()
    .Select(p => p.HasDefaultValue ? p.RawDefaultValue : GetDefaultValue(p.ParameterType))
    .ToArray();
当有更多参数时,如何执行此操作? 我需要创建对象来读取属性:

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

您可以创建一个助手方法来获取类型的默认值:

private static object GetDefaultValue(Type type)
{
    if (type.IsEnum) return type.GetEnumValues().GetValue(0);
    if (type.IsValueType) return Activator.CreateInstance(type);
    return null;
}
然后,您可以获得参数的默认值:

var parameters = constructor.GetParameters()
                            .Select(p => GetDefaultValue(p.ParameterType))
                            .ToArray();
并调用
ConstructorInfo
以获取实例:

var obj = constructor.Invoke(parameters);

如果构造函数的参数具有默认值,并且您希望使用它们,则可以执行以下操作:

object curObject = Activator.CreateInstance(classType, new object[] { parameters[0].ParameterType.GetEnumValues().GetValue(0) });
var parameters = constructor
    .GetParameters()
    .Select(p => p.HasDefaultValue ? p.RawDefaultValue : GetDefaultValue(p.ParameterType))
    .ToArray();

您可以创建自己的工厂,并编写一个方法,用于检查构造函数的类型,并使用默认值运行第一个参数化的构造函数:

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);
    }
}
附言。 这是一本书

更新:

代码会根据您使用的场景进行更改。现在我们有两种方法, 一个返回对象,另一个可以将其转换为T类型


我还更新了DotnetFiddle,请检查。

你好,Fabjan,感谢您提供此解决方案。有一个问题。我只有在运行时读取的类类型。我不知道编译时的对象(类)名称。您的代码:var curObject=MyFactory.MyCreateInstance(类类型);不适用于object关键字。我已经在DotNetFiddle上更新了我的答案和代码示例。谢谢,它工作得很好。你知道constructor.Invoke和Activator.CreateInstance的区别吗?Arturo,constructor.Invoke和Activator.CreateInstance的区别是什么?你能用Activator.CreateInstance做同样的事情吗?@Simon:
Constructor.Invoke
直接调用该构造函数
Activator.CreateInstance
创建一个实例,查找与指定参数最匹配的构造函数。