可能的解决方案,基于使用表达式树。此解决方案的优点是,当您的类型的第一个实例被创建时,慢反射机制只使用一次。
//public fields are of this type
public class TestClass
{
}
//Class with public fields
public class TestContainerClass
{
public TestClass TestClassField1;
public TestClass TestClassField2;
public TestClass TestClassField3;
public TestClass TestClassField4;
//should fill this list on creation of first instance and then use it
//assume that type is not changed in a runtime
private static List<Action<TestContainerClass,TestClass>> _fieldInitializers;
public TestContainerClass()
{
if (_fieldInitializers == null)
{
_fieldInitializers = new List<Action<TestContainerClass, TestClass>>();
//use reflection only once
FieldInfo[] testClassFieldInfos =
this.GetType().GetFields().Where(f => f.FieldType == typeof (TestClass)).ToArray();
foreach (var testClassFieldInfo in testClassFieldInfos)
{
//get action to set current field and store it in a list
var fieldSetter = GetFieldAssigner<TestContainerClass, TestClass>(testClassFieldInfo);
_fieldInitializers.Add(fieldSetter);
}
}
//next lines will set all
foreach (var fieldInitializer in _fieldInitializers)
{
fieldInitializer(this,new TestClass());
}
}
public static Action<T, I> GetFieldAssigner<T, I>(FieldInfo fieldInfo)
{
ParameterExpression targetExp =
Expression.Parameter(typeof(T), "target");
ParameterExpression valueExp =
Expression.Parameter(typeof(I), "value");
MemberExpression fieldExp = Expression.Field(targetExp, fieldInfo);
BinaryExpression assignExp = Expression.Assign(fieldExp, valueExp);
var setter = Expression.Lambda<Action<T, I>>(assignExp, targetExp, valueExp).Compile();
return setter;
}
}
另外,我想注意到,当你结合初始化和声明字段时,你可能会发现你的构造函数有点臃肿,像这样:
class SomeType
{
private int _x = 12;//declare and init
public SomeType()
{
_x = 12;//compiler inserted that line
}
public SomeType(BlahBlahType blahBlahObject)
{
_x = 12;//compiler inserted that line
}
//other constructors will also have _x = 12; line
}