2010-01-11 16 views
8

Non so se questo è possibile, ma in alcuni dei miei test di unità, finisco per inizializzare oggetti diversi con gli stessi argomenti. Mi piacerebbe essere in grado di memorizzare tali argomenti in qualche variabile e solo inizializzare il costruttore dell'oggetto multi-parametro con la variabile così invece di fare:C# argomenti multipli in uno per DRY out passare parametri

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

ho potuto effettuare le seguenti operazioni:

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

Esiste un modo per farlo senza sovrascrivere il costruttore di Thing per fare una lista che esplode manualmente e coglie argomenti? Forse qualche zucchero sintattico in C#?

+1

No, si desidera utilizzare Rubino =). –

+2

L'argomento di Python decomprimere è una benedizione! –

+1

Ho pensato _ a me stesso che, se stavo usando Ruby in questo progetto, non avrei dovuto fare questa domanda. –

risposta

13

Voglio dire, c'è questo:

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

Basta essere attenti di closure semantics.

+1

sì, è come un InLine piccolo ObjectFactory, ma tieni in considerazione che se arg1-arg4 sono tipi di riferimento, allora tutte le tue cose condivideranno quegli oggetti, se sono di valore o non ti interessa se sono condivisi, allora questo è probabilmente il più semplice –

+0

Nel mio caso, arg1-4 sono stringhe, quindi va tutto bene. –

1

C'è anche questo, supponendo che il Thing1 è un oggetto banale, e basta un copia superficiale:

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

Si potrebbe anche usare un array di oggetti e di un ciclo for, se avete bisogno di fare questo molti volte.

1

Potresti riscrivere lo in qualcosa come GimmieAThing<T> usando un po 'di generici?

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

Beh credo che si potrebbe utilizzare un contenitore CIO, dal momento che molti di questo anche offrire un ObjectFactory, cioè dite il CIO come fare una nuova istanza di tipo T e poi basta chiedere al CIO di darvi un esempio di esso.

Tuttavia, se non volete ottenere un CIO, si potrebbe fare voi stessi un po 'di classe fabbrica

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); 
    } 
} 

tuttavia tenere presente che se gli argomenti non sono di tipo di valore, allora tutte le istanze di Thing volontà avere riferimenti agli stessi oggetti, quindi, anche se avete diverse istanze di cose, punterebbero tutte allo stesso argomento1. Che cosa si potrebbe fare per risolvere che è quello di prendere in realtà in una Func nel parametro, in modo da poter effettivamente creare uno nuovo:

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()); 
    } 
} 

e si dovrebbe chiamare in questo modo:

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


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

e otterresti una nuova istanza di Thing ogni volta, ognuno con i propri oggetti di proprietà.

+1

public MagicFactory ? – gingerbreadboy

1

Suggerirei di esaminare il modello Test Data Builder. Funziona molto bene quando hai molti parametri che desideri variare in modo indipendente, riuso e così via.

È possibile utilizzare il metodo properties + object initializers for 'flat' classes o il concatenamento del metodo fluido in alternativa. Ho giocato con entrambi e ognuno ha i suoi vantaggi.

Vantaggi:

  • È possibile catturare le variabili/valori che sono stati utilizzati per costruire un oggetto
  • È possibile riutilizzare un'istanza costruttore se i valori che ci vuole sono tipi semplici e/o immutabili (tipi di valore, stringhe ecc)
  • È possibile variare ogni cTOR parametro indipendentemente senza rumore /code duplicazione rende le prove leggere molto bene come, invece di dovendo ricordare quale parametro di ctor è quale, si vede il nome.

Se è necessario creare nuove istanze di ciascun parametro, controlla la risposta di bangoker.

Comunque, ecco qualche codice:

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); 
    } 
} 

Usage (una volta esempio):

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

più istanze:

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

utilizzare la dichiarazione params nel metodo in questo modo:

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

e vi permetterà di effettuare le seguenti operazioni:

result = Things(arg1) 
result = Things(arg1,arg2) 
result = Things(arg1,arg2,arg3) 
result = Things(arg1,arg2,arg3,arg4) 
Problemi correlati