反思 - 调用构造函数参数

问题描述:

我从加载的程序集读取类型,例如:反思 - 调用构造函数参数

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

如果counstructor有参数,我能读懂他们:

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

我想调用默认的构造函数参数值或者如果参数是枚举,则使用第一个枚举值。 如果只有一个参数,它是枚举,它的工作原理是这样的:

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

我怎么能做到这一点的时候有更多的参数呢? 我需要创建对象读取属性:

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

好了,你可以创建自己的工厂,并编写方法,即检查类的构造函数使用默认参数:

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

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

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

然后你就可以用这个方法:

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. 这是DotNet fiddle example

更新:

的代码是根据你一起工作的场景改变。现在我们有两种方法,一种返回对象 ,另一种可以将其转换为T型。

我也更新了DotnetFiddle,请检查它。

+0

嗨,Fabjan,谢谢你的解决方案。有一个问题。 我只有classType,我在运行时读取。我不知道在编译时的对象(类)名称。你的代码:var curObject = MyFactory.MyCreateInstance (classType);不支持object关键字。 – Simon

+0

我已经更新了我的答案以及DotNetfiddle上的代码示例 – Fabjan

+0

谢谢,它完美无缺。你知道constructor.Invoke与Activator.CreateInstance之间的区别吗? – Simon

你可以做一个辅助方法来获得一个类型的默认值:

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); 

如果构造函数的参数有默认值,你要使用它们,你可以做这样的事情:

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

Arturo,constructor.Invoke与Activator.CreateInstance有什么区别?你可以用Activator.CreateInstance做同样的事吗? – Simon

+0

@Simon:'Constructor.Invoke'直接调用该构造函数。 'Activator.CreateInstance'创建一个实例,查找与指定参数最匹配的构造函数。 –