Usando "nuovo" in una proiezione?

3

Desidero proiettare una raccolta da un tipo ( Something ) a un altro tipo ( SomethingElse ). Sì, questa è una domanda molto aperta, ma quale delle due opzioni seguenti preferisci?

Creazione di una nuova istanza utilizzando new :

var result = query.Select(something => new SomethingElse(something));

Utilizzo di una factory:

var result = query.Select(something => SomethingElse.FromSomething(something));

Quando penso a una proiezione, generalmente la considero una conversione . L'utilizzo di new mi dà l'idea che sto creando nuovi oggetti durante una conversione, il che non sembra giusto. Semanticamente, SomethingElse.FromSomething() si adatta sicuramente meglio. Anche se la seconda opzione richiede un codice addizionale per impostare una fabbrica, che potrebbe diventare inutilmente compulsivo.

    
posta davenewza 09.11.2012 - 12:22
fonte

5 risposte

1

Questa domanda sembra essere più sull'adeguatezza dell'uso di un metodo factory rispetto a una chiamata al costruttore diretto. Il mio esempio preferito utilizza il tipo TimeSpan perché ha diversi overload di costruttore e diversi metodi factory statici FromXXX.

// how easily can you spot the bug?
int[] durationMs = { 1, 2, 3, 4 };

IEnumerable<TimeSpan> durations1 = 
    durationMs.Select(ms => new TimeSpan(0, 0, ms));

IEnumerable<TimeSpan> durations2 =
    durationMs.Select(ms => TimeSpan.FromSeconds(ms));

Quale espressione era più facile da individuare nelle due proiezioni equivalenti? Anche la correzione delle due espressioni è interessante:

// spot the bug after the fix?
IEnumerable<TimeSpan> durations1 = 
    durationMs.Select(ms => new TimeSpan(0, 0, 0, ms));

IEnumerable<TimeSpan> durations2 =
    durationMs.Select(ms => TimeSpan.FromMilliseconds(ms));

L'espressione durations2 è corretta (correzione bug). Tuttavia, l'aggiunta di un solo parametro 0 alla chiamata del costruttore durations1 non era sufficiente - dobbiamo aggiungere un altro 0 - passando dalla versione a 3 parametri alla versione a 5 parametri per specificare millisecondi (come documentato su msdn ).

Il libro "Linee guida per la progettazione di framework" contiene alcuni ottimi consigli su quando fornire metodi di produzione statici . Il libro va più nel dettaglio su ogni punto, mentre il link che ho fornito riassume semplicemente il consiglio. Spero che questo aiuti.

    
risposta data 08.12.2012 - 15:46
fonte
3

In .NET Framework, la convenzione più utilizzata è:

something.ToSomethingElse();

Esempi:

  • 37.ToString();

  • new [] { "Hello", "World" }.ToArray();

  • DateTime.Now.ToBinary();

  • Guid.Empty.ToByteArray();

  • ecc.

Tieni presente che, a seconda del contesto, potresti semplicemente utilizzare Enumerable.Cast :

var result = query.Cast<SomethingElse>();

Se hai una buona ragione per evitare questa convenzione (ad esempio se SomethingElse è una stringa), usa la convenzione che preferisci tra quelle citate nella tua domanda. Sono entrambi validi.

Un'altra cosa bella in C # è l'operatore implicito. Ad esempio, anziché:

var element = new XElement(new XName("section"), ...);

scrivi semplicemente:

var element = new XElement("section"); // Uses implicit conversion from string to XName.
    
risposta data 09.11.2012 - 12:32
fonte
1

Il problema con il secondo approccio è che richiede un tipo denominato (al contrario di un anonimo ); altrimenti, sarebbe impossibile passare something a un metodo factory. Un'ampia percentuale di query LINQ non banali utilizza tipi anonimi, ad esempio

query.Zip(otherQuery, (a, b) => new {First = a, Second = b}).Select(...)

o

query.Select((v,i)=> new {Value=v, Index=i}).Where(...).Select(...)

e così via. Dover definire un tipo con nome per il tipo anonimo o utilizzare un generico Tuple<...> risolverebbe il problema a scapito della leggibilità.

L'utilizzo di new , d'altra parte, ti consente di rimanere coerente anche quando entri nel territorio di query LINQ non banali. Raccomanderei sicuramente di rimanere con new , evitando di rendere le questioni che sono già complesse anche più complesse senza una buona ragione.

    
risposta data 09.11.2012 - 12:51
fonte
0

Se vuoi cambiare un tipo in un altro tipo, ma non vuoi usare il codice sopra ogni volta .. usa automapper. È possibile tramite questa traduzione e più riutilizzo del codice.

link

fammi sapere se hai bisogno di evidenziare lo stesso.

    
risposta data 09.11.2012 - 12:33
fonte
0

Personalmente sceglierei la prima opzione se è usata solo in un posto o se crei un metodo di estensione se è usata in più posti.

    
risposta data 09.11.2012 - 12:34
fonte

Leggi altre domande sui tag