29

静的ファクトリ メソッドを持つクラスがあります。ファクトリを呼び出してクラスのインスタンスを取得し、できれば c# オブジェクト初期化構文を使用して、追加の初期化を行います。

MyClass instance = MyClass.FactoryCreate()
{
  someProperty = someValue;
}

MyClass instance = MyClass.FactoryCreate();
instance.someProperty = someValue;
4

7 に答える 7

29

いいえ。あるいは、ラムダを引数として受け入れることもできます。これにより、「作成」プロセスのどの部分が呼び出されるかを完全に制御することもできます。このようにあなたはそれを次のように呼ぶことができます:

MyClass instance = MyClass.FactoryCreate(c=>
   {
       c.SomeProperty = something;
       c.AnotherProperty = somethingElse;
   });

作成は次のようになります。

public static MyClass FactoryCreate(Action<MyClass> initalizer)
{
    MyClass myClass = new MyClass();
    //do stuff
    initializer( myClass );
    //do more stuff
    return myClass;
}

別のオプションは、代わりにビルダーを返すことです(MyClassへの暗黙のキャスト演算子を使用)。あなたはどちらを好きだと思いますか:

MyClass instance = MyClass.FactoryCreate()
   .WithSomeProperty(something)
   .WithAnotherProperty(somethingElse);

ビルダーのためにこれをチェックしてください

これらのバージョンは両方ともコンパイル時にチェックされ、完全なインテリセンスをサポートしています。


デフォルトのコンストラクターを必要とする3番目のオプション:

//used like:
var data = MyClass.FactoryCreate(() => new Data
{
    Desc = "something",
    Id = 1
});
//Implemented as:
public static MyClass FactoryCreate(Expression<Func<MyClass>> initializer)
{
    var myclass = new MyClass();
    ApplyInitializer(myclass, (MemberInitExpression)initializer.Body);
    return myclass ;
}
//using this:
static void ApplyInitializer(object instance, MemberInitExpression initalizer)
{
    foreach (var bind in initalizer.Bindings.Cast<MemberAssignment>())
    {
        var prop = (PropertyInfo)bind.Member;
        var value = ((ConstantExpression)bind.Expression).Value;
        prop.SetValue(instance, value, null);
    }
}

コンパイル時にチェックされる場合とチェックされない場合の中間です。割り当てに一定の式を強制するため、いくつかの作業が必要です。それ以外は、すでに回答にあるアプローチのバリエーションだと思います。通常の割り当ても使用できることを忘れないでください。本当にこれが必要かどうかを検討してください。

于 2009-03-23T23:08:08.603 に答える
2

「いいえ」に+1。

匿名オブジェクトの方法に代わる方法は次のとおりです。

var instance = MyClass.FactoryCreate(
    SomeProperty => "Some value",
    OtherProperty => "Other value");

この場合FactoryCreate()、次のようになります。

public static MyClass FactoryCreate(params Func<object, object>[] initializers)
{
    var result = new MyClass();
    foreach (var init in initializers) 
    {
        var name = init.Method.GetParameters()[0].Name;
        var value = init(null);
        typeof(MyClass)
            .GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase)
            .SetValue(result, value, null);
    }
    return result;
}
于 2009-03-23T23:30:23.870 に答える
1

みんなが言ったように、違います。

引数としてのラムダはすでに提案されています。
より洗練されたアプローチは、匿名を受け入れ、オブジェクトに応じてプロパティを設定することです。すなわち

MyClass instance = MyClass.FactoryCreate(new {
    SomeProperty = someValue,
    OtherProperty = otherValue
});

ただし、オブジェクトはすべてのプロパティに反映される必要があるため、これははるかに遅くなります。

于 2009-03-23T23:12:28.733 に答える
1

いいえ、オブジェクト初期化子は、コンストラクターを使用した "new" の呼び出しでのみ使用できます。オプションの 1 つは、ファクトリ メソッドにいくつかの引数を追加して、ファクトリ内でオブジェクトを作成するときにそれらの値を設定することです。

MyClass instance = MyClass.FactoryCreate(int someValue, string otherValue);
于 2009-03-23T22:57:35.460 に答える
0

いいえ、それは「インライン」でしかできないことです。ファクトリ関数ができることは、参照を返すことだけです。

于 2009-03-23T22:58:57.983 に答える