Est-il possible d’utiliser un initialiseur d’object ac # avec une méthode fabrique?

J’ai une classe avec une méthode de fabrique statique sur elle. Je souhaite appeler la fabrique pour récupérer une instance de la classe, puis effectuer une initialisation supplémentaire, de préférence via la syntaxe d’initialisation d’object c #:

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

contre

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

Sinon, vous pouvez accepter un lambda en tant qu’argument, ce qui vous donne également le contrôle total sur la partie du processus de “création” qui sera appelée. De cette façon, vous pouvez l’appeler comme suit:

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

La création ressemblerait à:

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

Une autre option consiste à renvoyer un générateur à la place (avec un opérateur de conversion implicite vers MyClass). Ce que vous appelleriez comme:

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

Cochez cette case pour le constructeur

Ces deux versions sont vérifiées au moment de la compilation et supportent pleinement intellisense.


Une troisième option qui nécessite un constructeur par défaut:

 //used like: var data = MyClass.FactoryCreate(() => new Data { Desc = "something", Id = 1 }); //Implemented as: public static MyClass FactoryCreate(Expression> 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()) { var prop = (PropertyInfo)bind.Member; var value = ((ConstantExpression)bind.Expression).Value; prop.SetValue(instance, value, null); } } 

C’est un milieu entre vérifié au moment de la compilation et non vérifié. Cela nécessite un peu de travail, car il force une expression constante dans les affectations. Je pense que tout le rest sont des variations des approches déjà dans les réponses. Rappelez-vous que vous pouvez également utiliser les tâches normales, demandez-vous si vous en avez vraiment besoin.

Vous pouvez utiliser une méthode d’extension telle que:

 namespace Utility.Extensions { public static class Generic { ///  /// Initialize instance. ///  public static T Initialize(this T instance, Action initializer) { initializer(instance); return instance; } } } 

Vous l’appelleriez comme suit:

 using Utility.Extensions; // ... var result = MyClass.FactoryCreate() .Initialize(x => { x.someProperty = someValue; x.someProperty2 = someValue2; }); 

+1 sur “non”.

Voici une alternative à la manière d’object anonyme:

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

Dans ce cas, FactoryCreate() serait quelque chose comme:

 public static MyClass FactoryCreate(params Func[] 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; } 

Non, l’initialiseur d’object ne peut être utilisé que sur un appel à “new” avec le constructeur. Une option pourrait être d’append des arguments supplémentaires à votre méthode d’usine afin de définir ces valeurs lors de la création d’objects dans l’usine.

 MyClass instance = MyClass.FactoryCreate(int someValue, ssortingng otherValue); 

Comme tout le monde l’a dit, non.

Un lambda comme argument a déjà été suggéré.
Une approche plus élégante consisterait à accepter un nom anonyme et à définir les propriétés en fonction de l’object. c’est à dire

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

Ce serait beaucoup plus lent cependant, car l’object devrait être réfléchi pour toutes les propriétés.

Non, c’est quelque chose que vous ne pouvez faire qu’en ligne. La fonction usine ne peut que vous retourner une référence.