在我尝试回答之前,我不得不指出你正在做的事情似乎是多余的。假设您将此代码放入构造函数中,生成如下内容:
public class Foo
{
private int a;
private bool b;
private SomeType c;
public Foo()
{
this.a = default(int);
this.b = default(bool);
this.c = default(SomeType);
}
}
是不必要的。当一个类被构建时,这已经自动发生了。(事实上,一些快速测试表明,如果这些分配在构造函数中显式完成,它们甚至不会被优化掉,尽管我认为 JITter 可以解决这个问题。)
其次,该default
关键字的设计很大程度上是为了完成您正在做的事情:提供一种将“默认”值分配给编译时类型未知的变量的方法。我假设它是为通用代码使用而引入的,但自动生成的代码在使用它时当然也是正确的。
请记住,default
引用类型的值是null
,所以
this.list = default(List<int>);
不构造一个新的List<int>
,它只是设置this.list
为null
。相反,我怀疑您想要做的是使用该Type.IsValueType
属性将值类型保留为其默认值,并使用new
.
最后,我认为您在这里寻找的是类的IsGenericType
属性Type
和相应的GetGenericArguments()
方法:
foreach (PropertyInfo property in properties)
{
if (property.Type.IsGenericType)
{
var subtypes = property.Type.GetGenericArguments();
// construct full type name from type and subtypes.
}
else
{
code += "this." + property.Name + " = default(" + property.PropertyType.Name + ")";
}
}
编辑:
至于构造对引用类型有用的东西,我看到生成的代码使用的一种常见技术是为您希望使用的任何类都需要一个无参数构造函数。Type.GetConstructor()
通过调用、传入一个空Type[]
(例如Type.EmptyTypes
)并查看它是否返回一个ConstructorInfo
或,很容易查看一个类是否具有无参数构造函数null
。一旦确定了,只需替换default(typename)
为即可new typename()
满足您的需求。
更一般地,您可以为该方法提供任何类型的数组,以查看是否有匹配的构造函数,或者调用GetConstructors()
以获取所有类型。这里要注意的是IsPublic
,IsStatic
和 ,IsGenericMethod
的字段ConstructorInfo
,以找到您可以从生成此代码的任何位置实际调用的字段。
但是,您尝试解决的问题将变得任意复杂,除非您可以对其施加一些限制。一种选择是找到一个任意构造函数并构建一个如下所示的调用:
var line = "this." + fieldName + " = new(";
foreach ( var param in constructor.GetParameters() )
{
line += "default(" + param.ParameterType.Name + "),";
}
line = line.TrimEnd(',') + ");"
(请注意,这仅用于说明目的,我可能会在这里使用 CodeDOM,或者至少使用 StringBuilder :)
但是,当然,现在您遇到了为每个参数确定适当类型名称的问题,它们本身可能是泛型。并且引用类型参数将全部初始化为 null。并且没有办法知道你可以从任意数量的构造函数中选择哪个实际上产生了一个可用的对象(其中一些可能会做坏事,比如假设你要在构造实例后立即设置属性或调用方法。)
How you go about solving those issues is not a technical one: you can recursively apply this same logic to each parameter as far down as you're willing to go. It's a matter of deciding, for your use case, how complex you need to be and what kind of limits you're willing to place on the users.