2010-01-11 6 views
8

No sé si esto es posible, pero en algunas de las pruebas de mi unidad, termino inicializando diferentes objetos con los mismos argumentos. Me gustaría ser capaz de almacenar los argumentos de alguna variable y solo inicializar el constructor de objetos de múltiples parámetros con esa variable así que en vez de hacer:C# argumentos múltiples en uno para SECAR el paso de parámetros

Thing thing1 = new Thing(arg1, arg2, arg3, arg4); 
Thing thing2 = new Thing(arg1, arg2, arg3, arg4); 
Thing thing3 = new Thing(arg1, arg2, arg3, arg4); 

que podía hacer lo siguiente:

MagicalArgumentsContainer args = (arg1, arg2, arg3, arg4); 
Thing thing1 = new Thing(args); 
Thing thing2 = new Thing(args); 
Thing thing3 = new Thing(args); 

¿Hay alguna forma de hacerlo sin anular el constructor de Thing para tomar una lista que explota manualmente y arranca argumentos? Tal vez un poco de azúcar sintáctico C#?

+1

n, que desea utilizar Rubí =). –

+2

¡El desempaquetado de argumentos de Python es una bendición! –

+1

Yo _idid_ pienso que, si estuviera usando Ruby en este proyecto, no habría tenido que hacer esta pregunta. –

Respuesta

13

quiero decir, hay esto:

Func<Thing> f =() => new Thing(arg1, arg2, arg3, arg4); 
Thing thing1 = f(); 
Thing thing2 = f(); 
Thing thing3 = f(); 
Thing thing4 = f(); 

Sólo tenga cuidado de closure semantics.

+1

sí, eso es como un objeto pequeño en miniatura de ObjectFactory, pero ten en cuenta que si arg1-arg4 son tipos de referencia, todas tus cosas compartirán esos objetos, si son de valor o si no te importa si se comparten, entonces esa es probablemente la más fácil –

+0

En mi caso, arg1-4 son cadenas, así que todo está bien. –

1

También hay esto, suponiendo que su thing1 es un objeto trivial, y sólo tiene una copia superficial:

Thing thing1 = new Thing(arg1, arg2, arg3, arg4); 
Thing thing2 = (Thing)thing1.MemberwiseClone(); 
0

También es posible usar una matriz de objetos y un bucle si tiene que hacer esto muchas veces.

1

¿Podría quizás reescribir GimmieAThing a algo así como GimmieAThing<T> usando un poco de genéricos?

public class MagicalArgumentsContainer 
    { 
      object[] _myParams; 

      public MagicalArgumentsContainer (params object[] myParams) 
      { 
      _myParams = myParams; 
      } 

      public Thing GimmieAThing() 
      { 
    return new Thing(_myParams[0], _myParams[1], _myParams[2], _myParams[3]); 
     } 
    } 
3

Bueno, yo supongo que se podría utilizar un contenedor IoC, ya que varios de esto también ofrecer una ObjectFactory, es decir, le dice al COI cómo hacer una nueva instancia de tipo T y luego le preguntas al COI para darle una instancia de eso.

Sin embargo, si usted no quiere tener una COI, se le podría caer un poco de clase de fábrica

public MagicFactory 
{ 
    T arg1, T2 arg2, T3 arg3,.., TN argN; 

    public MagicFactory(T1 a1,..., TN aN) 
    { 
     this.arg1=a1; 
     ... 
     this.argN = an; 
    } 

    public Thing GimmeDaThing() 
    { 
     return new Thing(this.arg1,...,this.argN); 
    } 
} 

Sin embargo, tenga en cuenta que si los argumentos no son del tipo de valor, a continuación, todas las instancias de Thing se tener referencias a los mismos objetos, por lo tanto, aunque tenga una instancia diferente de Cosas, todos apuntarían a la misma arg1. Lo que podría hacer para arreglar esto es tomar realmente en un Func en el parámetro, por lo que en realidad se puede crear una nueva:

public MagicFactory 
{ 
    Func<T1> arg1, ,.., Func<TN> argN; 

    public MagicFactory(Func<T1> a1,..., Func<TN> aN) 
    { 
     this.arg1=a1; 
     ... 
     this.argN = an; 
    } 

    public Thing GimmeDaThing() 
    { 
     return new Thing(this.arg1(),...,this.argN()); 
    } 
} 

y que le llame así:

var magicContainer = new MagicFactory(()=> new T1(...),...,()=>new T2(..); 


var thing1 = magicContainer.GimmeDaThing(); 
var thing1 = magicContainer.GimmeDaThing(); 
var thing1 = magicContainer.GimmeDaThing(); 
var thing1 = magicContainer.GimmeDaThing(); 

y obtendría una instancia nueva de Thing cada vez, cada una con sus propios objetos de propiedad.

+1

public MagicFactory ? – gingerbreadboy

1

Sugeriría mirar en el patrón Test Data Builder. Funciona muy bien cuando tiene muchos parámetros que desea variar de forma independiente, reutilizar, etc.

Puede usar properties + object initializers for 'flat' classes, o el método de encadenamiento de fluido como alternativa. He jugado con ambos y cada uno tiene sus ventajas.

Beneficios:

  • Puede capturar las variables/valores que fueron utilizados para construir un objeto
  • puede volver a utilizar una instancia constructor si los valores que toma son tipos simples y/(o tipos de valores, etc.) cadenas inmutables
  • puede variar cada ctor parámetro de forma independiente sin ruido /duplicación de código hace que las pruebas leído muy bien como, en lugar de teniendo que recordar qué ctor param es que, verá el nombre.

Si necesita crear nuevas instancias de cada parámetro, consulte la respuesta de bangoker.

De todos modos, aquí hay un código:

public class ThingBuilder 
{ 
    // set up defaults so that we don't need to set them unless required 
    private string m_bongoName = "some name"; 
    private DateTime m_dateTime = new DateTime(2001, 1, 1); 
    private int m_anotherArg = 5; 
    private bool m_isThisIsGettingTedious = true; 

    public ThingBuilder BongoName(string bongoName) 
    { 
     m_bongoName = bongoName; 
     return this; 
    } 

    public ThingBuilder DateTime(DateTime dateTime) 
    { 
     m_dateTime = dateTime; 
     return this;  
    } 

    // etc. for properties 3...N 

    public Thing Build() 
    {  
     return new Thing(m_bongoName, m_dateTime, m_anotherArg, m_isThisGettingTedious); 
    } 
} 

uso (una vez ejemplo):

// notice that the parameters are now explicitly named + readable! 
Thingy builtInstance = new ThingBuilder() 
          .BongoName("um bongo") 
          .DateTime(DateTime.Now) 
          .GettingTedious(true) 
          .Build(); 

varias instancias:

var builder = new ThingBuilder() 
        .BongoName("um bongo") 
        .DateTime(DateTime.Now) 
        .GettingTedious(true); 

// let's make multiple objects 
Thing builtThing = builder.Build(); 
Thing anotherBuiltThing = builder.Build(); 
1

Uso de la declaración params en su método de este modo:

public Thing(params string[] args) 
{ 
    foreach(string s in args) 
    { 
     ... 
    } 
} 

y se le permitirá hacer lo siguiente:

result = Things(arg1) 
result = Things(arg1,arg2) 
result = Things(arg1,arg2,arg3) 
result = Things(arg1,arg2,arg3,arg4) 
Cuestiones relacionadas