Domanda

Ciò è correlato alle convenzioni utilizzate in C#.

Ho un metodo che ha due parametri (coordinate X e Y).Queste coordinate rappresentano la posizione in cui può risiedere una "tesserina".Se una tessera risiede in queste coordinate, il metodo restituisce il suo numero.Se nessuna tessera risiede in queste coordinate, mi chiedo come dovrebbe comportarsi il metodo.

Vedo tre opzioni:

  1. Usa le eccezioni.Posso sollevare un'eccezione ogni volta che il metodo non trova alcun riquadro.Tuttavia, poiché questa situazione non è rara, questa opzione è la peggiore.
  2. Fallo alla vecchia maniera C++ e restituisci -1 se non è presente alcun riquadro.
  3. Rendi il numero del riquadro un parametro di riferimento e modifica il tipo di metodo restituito in booleano per mostrare se esiste o meno un riquadro.Ma questo mi sembra un po' complicato.

Quindi cosa dovrei fare?

È stato utile?

Soluzione

Return -1.

Questa non è solo una convenzione C ++, è comune anche in .NET Framework - per esempio metodi come String.IndexOf o immobili come SelectedIndex per i controlli che rappresentano liste.

Modifica

Proprio per elaborare, delle tre opzioni a tua domanda (Exception, restituire -1, fuori parametro), restituendo -1 è la strada da percorrere. Le eccezioni sono per situazioni eccezionali, e la Microsoft codifica linee guida raccomanda di evitare i punti principali, se possibile.

A mio parere il ritorno -1 (a condizione che sta andando sempre essere un valore non valido), che restituisce un int nullable, o la restituzione di un oggetto delle mattonelle sono tutte soluzioni accettabili, e si dovrebbe scegliere quale è più coerente con il resto della vostra applicazione . Non riesco a immaginare ogni sviluppatore avrebbe avuto la minima difficoltà con uno dei seguenti:

int tileNumber = GetTile(x,y);
if  (tileNumber != -1)
{
   ... use tileNumber ...
}


int? result = GetTile(x,y);
if (result.HasValue)
{
    int tileNumber = result.Value; 
   ... use tileNumber ...
}


Tile tile = GetTile(x,y);
if (tile != null)
{
   ... use tile ...
}

Non sono sicuro di aver capito il commento di Peter Ruderman sull'utilizzo di un int di essere "molto più efficiente di restituire un tipo nullable". Avrei pensato alcuna differenza sarebbe trascurabile.

Altri suggerimenti

È possibile restituire null, e verificare la presenza di questo sul codice chiamante.

Naturalmente dovreste usare un tipo nullable:

int? i = YourMethodHere(x, y);

Le eccezioni riguardano casi eccezionali, quindi utilizzare le eccezioni su a conosciuto E previsto la situazione di errore è "cattiva".Inoltre, ora è più probabile che tu abbia try-catch ovunque per gestire questo errore in modo specifico perché ti aspetti che si verifichi questa situazione di errore.

Rendere il valore restituito un parametro è accettabile se la tua unica condizione di errore (diciamo -1) è confondibile con un valore reale.Se puoi avere un numero di tessera negativo, questo è un modo migliore di procedere.

Un int nullable è una possibile alternativa a un parametro di riferimento ma stai creando oggetti con questo, quindi se un "errore" è di routine potresti fare più lavoro in questo modo rispetto a un parametro di riferimento.Come ha sottolineato Roman in un commento altrove, avrai C# vs.Problemi con VB il tipo nullable viene introdotto troppo tardi perché VB possa fornire un buon zucchero sintattico come C#.

Se le tue tessere possono essere solo non negative, restituire -1 è un modo accettabile e tradizionale per indicare un errore.Sarebbe anche il meno costoso in termini di prestazioni e memoria.


Un'altra cosa da considerare è l'autodocumentazione.L'uso di -1 e un'eccezione è una convenzione:dovresti scrivere la documentazione per assicurarti che lo sviluppatore ne sia a conoscenza.Utilizzando un int? return o un parametro di riferimento si autodescriverebbe meglio e non lo farebbe richiedere documentazione affinché uno sviluppatore sappia come gestire la situazione di errore.Naturalmente :) dovresti sempre scrivere la documentazione, proprio come dovresti usare il filo interdentale ogni giorno.

Usa un valore di ritorno annullabile.

int? GetTile(int x, int y) {
   if (...)
      return SomeValue;
   else
      return null;
}

Questa è la soluzione più chiara.

Se il metodo ha accesso agli oggetti sottostanti piastrelle, un'altra possibilità sarebbe di restituire l'oggetto piastrella stessa, oppure null se non esiste piastrelle.

Vorrei andare con l'opzione 2. Hai ragione, un'eccezione in un caso come comune può essere un male per le prestazioni, e l'utilizzo di un parametro out e restituzione di un vero o falso è utile ma irregolare da leggere.

Inoltre, pensare al metodo di string.IndexOf(). Se non viene trovato, restituisce -1. Mi piacerebbe seguire questo esempio.

Si potrebbe restituire -1, come questo è un approccio abbastanza comune # C. Tuttavia, potrebbe essere migliore per tornare in realtà la piastrella che è stato cliccato, e nel caso in cui nessuna tessera è stato cliccato, restituire un riferimento a un Singleton un'istanza NullTile. Il vantaggio di fare in questo modo è che si dà un significato concreto a ciascun valore restituito, piuttosto che essere solo un numero che non ha alcun significato intrinseco di là del suo valore numerico. Un tipo 'NullTile' è molto specifico per quanto riguarda il suo significato, lasciando poco a dubitare di altri lettori di codice.

Le opzioni migliori sono per restituire un valore booleano come bene o restituire null.

per es.

bool TryGetTile(int x, int y, out int tile);

o

int? GetTile(int x, int y);

Ci sono diversi motivi per preferire il modello "TryGetValue". Per uno, restituisce un valore booleano, quindi codice client è incredibilmente semplice, per esempio: se (TryGetValue (fuori someVal)) {/ * codice * /}. Confronta questo per codice client che richiede il confronto di valore sentinella hard-coded (a -1, 0, null, la cattura di un particolare insieme di eccezioni, ecc) "numeri magici" raccolto in fretta con quei disegni e factoring il tight-accoppiamento diventa un lavoro di routine.

Quando i valori sentinella, null, o eccezioni sono attesi è assolutamente vitale che si controlla la documentazione su cui viene utilizzato il meccanismo. Se la documentazione non esiste o non è accessibile, uno scenario comune, allora si deve inferire sulla base di altri elementi di prova, se si effettua la scelta sbagliata si sono semplicemente insediano per un'eccezione null-riferimento o altri difetti cattivi. Considerando che il TryGetValue () modello è abbastanza vicino alla auto-documentazione per il suo nome e la firma del metodo da solo.

ho la mia opinione sulla questione che lei ha chiesto, ma è detto sopra e ho votato di conseguenza.

Per quanto riguarda la domanda che non ha chiesto, o almeno come estensione a tutte le risposte di cui sopra: vorrei essere sicuri di mantenere la soluzione a situazioni simili coerenti in tutta l'applicazione. In altre parole, qualunque sia la risposta di stabilirsi su, mantenere lo stesso all'interno della app.

Se il metodo è parte di una libreria di basso livello, allora il vostro design standard .NET probabilmente impone che si passi eccezioni dal tuo metodo.

Questo è come il framework .NET funziona in generale. I chiamanti di livello superiore dovrebbero prendere le vostre eccezioni.

Tuttavia dal momento che sembra di fare questo da un thread dell'interfaccia utente, che ha implicazioni di prestazioni dal momento che si sta rispondendo a eventi dell'interfaccia utente - Faccio quello che Jay Riggs già suggerito, restituire null, e assicurarsi che i chiamanti verificare la presenza di un valore di ritorno Null .

Mi piacerebbe spezzare in due metodi. Avere qualcosa di simile CheckTileExists(x,y) e GetTile(x,y). Il primo restituisce un valore booleano che indica se v'è una piastrella nelle coordinate indicate. Il secondo metodo è essenzialmente quello di cui parli nel tuo post originale, tranne che dovrebbe generare un'eccezione quando date le coordinate non valide (dato che indica il chiamante non ha fatto prima CheckTileExists() chiamata, quindi è legittimamente una situazione eccezionale. Per la motivi d'urgenza, che vorreste probabilmente questi due metodi per condividere una cache, in modo che, in caso si chiamano uno dopo l'altro, l'overhead sulla funzione GetTile() sarebbe trascurabile. non so se si dispone già di un oggetto adatto per mettere questi metodi o se forse si dovrebbe fare loro due metodi su una nuova classe. IMHO, la pena di prestazioni di questo approccio è trascurabile e l'aumento del codice di chiarezza supera di gran lunga di esso.

E 'possibile che avete creato (o potrebbe creare) un oggetto Tile cui si fa riferimento alle coordinate? Se è così, si può restituire un riferimento a tale piastrelle o null se non ci sono mattonelle nelle coordinate indicate:

public Tile GetTile(int x, int y) {
    if (!TileExists(x, y)) 
        return null;
    // ... tile lookup here...
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top