1

私は、すべて同じタイプのメンバーが数十個ある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();」という部分です。私の意見では、冗長なノイズです。クラスを作成するときにこれらのフィールドを常に新しくすることができる良い方法はありますか?コンストラクターでリフレクションを使用すると、これがうまくいくと思います。特に、基本クラスに実装されている場合はそうです。誰かがこれを行うための最善の方法を袖口から知っていますか?

4

3 に答える 3

1

@Marcによって義務付けられた事実を除いて、ここで悪いコーディングスタイルを見ないでください。本当に正当な理由がない場合は、パブリックフィールドを使用しないでください。

ファイルの上でメンバーを初期化するのが本当に好きでない場合は、で初期化することができますが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

式ツリーの使用に基づく可能な解決策。このソリューションの利点は、タイプの最初のインスタンスが作成されたときに、低速反射メカニズムが1回だけ使用されることです。

//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 に答える