1

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

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

问题在于部分“= new ApiParameter();” 在我看来,是冗长的噪音。有没有一种好方法可以让我在创建课程时始终更新这些字段?我认为在构造函数中使用反射会很好地做到这一点 - 特别是如果在我的基类中实现。有谁知道袖手旁观如何最好地做到这一点?

4

3 回答 3

1

看不出有什么不好编码风格:如果没有很好的理由,请不要使用公共字段。

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

于 2012-08-04T15:22:35.013 回答
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());
     }
}
于 2012-08-04T17:57:20.513 回答
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 
}
于 2012-08-05T19:47:05.833 回答