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

本文关键字:成员 构造函数 实例化 希望 我的 懒惰 | 更新日期: 2024-09-27 10:20:28

我有一个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();"是冗长的噪音。有没有一种好的方法可以让这些字段在创建类时始终是新的?我认为在构造函数中使用反射可以很好地做到这一点,尤其是在基类中实现的情况下。有人知道如何最好地做到这一点吗?

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

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

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

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

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

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

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