懒惰 - 并希望我的所有公共成员在构造函数中实例化

时间:2012-08-04 15:17:34

标签: c# reflection constructor

我有一个C#类,它有几十个都是相同类型的成员,我总是希望它们是新的,而不是在实例化类时为null。所以在我的类字段声明中我写道:

public ApiParameter mnBatchNumber = new ApiParameter();
public ApiParameter szBatchType = new ApiParameter();
public ApiParameter jdBatchDate = new ApiParameter();
...// and so on, many many times

这个问题是“= new ApiParameter();”在我看来,是冗长的噪音。有没有一种好的方法可以让我在创建课程时总是将这些字段变为新的?我认为在构造函数中使用反射可以很好地完成这一点 - 特别是如果在我的基类中实现的话。有谁知道袖口怎么做最好?

3 个答案:

答案 0 :(得分:1)

除了@Marc提到的一个事实之外,没有看到任何编码风格:如果没有充分的理由,请不要使用公共字段。

如果真的不喜欢在文件顶部初始化成员,可能是,你可以在static constructor中初始化它们,但我再说一遍,我更喜欢你已经做过的方式,但在私人字段。

答案 1 :(得分:1)

以下是您可以在构造函数中使用的一些反射:

FieldInfo[] fields = this.GetType().GetFields(); //if you're using private fields use GetFields(BindingFlags.NonPublic)
foreach(FieldInfo f in fields){
     if(f.FieldType == typeof(ApiParameter)){
        f.SetValue(this, new ApiParameter());
     }
}

答案 2 :(得分:0)

可能的解决方案,基于使用表达式树。 此解决方案的优点是,在创建第一个类型实例时,慢速反射机制仅使用一次。

//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 
}