Come posso impostare un parametro su Guid.Empty in C #?


178

Vorrei dire:

public void Problem(Guid optional = Guid.Empty)
{
}

Ma il compilatore si lamenta che Guid.Empty non è una costante di tempo di compilazione.

Poiché non desidero modificare l'API, non posso usare:

 Nullable<Guid>


Cosa c'è di sbagliato nel passaggio a Nullable<Guid> optional = null(o più tersamente Guid? optional = null)? Qualsiasi Guida attualmente passata ad esso forzerà senza alcuna modifica del codice necessaria.
NH.

Risposte:


235

Soluzione

Puoi usare new Guid()invece

public void Problem(Guid optional = new Guid())
{
  // when called without parameters this will be true
  var guidIsEmpty = optional == Guid.Empty;
}

Puoi anche usare default(Guid)

default(Guid)funzionerà anche esattamente come new Guid().

Poiché Guid è un tipo di valore non di tipo di riferimento, quindi default(Guid)non è uguale, ad nullesempio, è uguale a chiamare il costruttore predefinito.

Ciò significa che questo:

public void Problem(Guid optional = default(Guid))
{
  // when called without parameters this will be true
  var guidIsEmpty = optional == Guid.Empty;
}

È esattamente lo stesso dell'esempio originale.

Spiegazione

Perché non ha Guid.Emptyfunzionato?

Il motivo per cui ricevi l'errore è perché Emptyè definito come:

public static readonly Guid Empty;

Quindi, è una variabile, non una costante (definita come static readonlynon come const). Il compilatore può avere solo valori noti del compilatore come valori predefiniti dei parametri del metodo (non noti solo in fase di esecuzione).

La causa principale è che non puoi avere constalcuno struct, a differenza enumad esempio. Se lo provi, non verrà compilato.

Ancora una volta la ragione è che structnon è un tipo primitivo.
Per un elenco di tutti i tipi primitivi in ​​.NET, vedere http://msdn.microsoft.com/en-gb/library/system.typecode.aspx
(notare che di enumsolito eredita int, che è una primitiva)

Ma new Guid()non è anche una costante!

Non sto dicendo che ha bisogno di una costante. Ha bisogno di qualcosa che possa essere deciso in fase di compilazione. Emptyè un campo, quindi il suo valore non è noto in fase di compilazione (solo all'inizio del tempo di esecuzione).

Il valore del parametro predefinito deve essere noto al momento della compilazione, che può essere un constvalore o qualcosa definito utilizzando una funzione C # che rende noto il valore al momento della compilazione, come default(Guid)o new Guid()(che viene deciso al momento della compilazione per structs poiché non è possibile modificare il structcostruttore in codice).

Mentre puoi fornire defaulto newfacilmente, non puoi fornire un const(perché non è un tipo primitivo o un enumcome spiegato sopra). Quindi, ancora una volta, non dicendo che il parametro opzionale stesso necessita di un valore noto costante, ma del compilatore.


5
Bene, non ha bisogno di un'espressione costante normale - new Guid()non è un'espressione costante, per esempio. Le specifiche C # definiscono chiaramente cosa è permesso, incluso ma non limitato a costanti. (Giusto per essere chiari, in modo efficace è una costante di tempo di compilazione, non solo una "espressione costante" in termini C # spec).
Jon Skeet,

3
Leggi la parte Spiegazione nella mia risposta. Aggiunto per rispondere a questa parte.
Meligy,

Bella spiegazione Grazie!
Daryl,

Puoi usare solo defaultoggigiorno :)
Joshit,

151

Guid.Emptyè equivalente a new Guid(), che è equivalente a default(Guid). Quindi puoi usare:

public void Problem(Guid optional = default(Guid))

o

public void Problem(Guid optional = new Guid())

Si noti che il new Foo()valore è applicabile solo quando:

  • Stai davvero chiamando il costruttore senza parametri
  • Foo è un tipo di valore

In altre parole, quando il compilatore sa che è davvero solo il valore predefinito per il tipo :)

(È interessante notare che sono sicuro al 99,9% che non chiamerà alcun new Foo()costruttore personalizzato che potresti aver creato. Non puoi creare tale costruttore in un tipo di valore in C #, ma puoi farlo in IL.)

È possibile utilizzare l' default(Foo)opzione per qualsiasi tipo.


Ora perché il messaggio di errore del compilatore non mi dice questo, il compilatore potrebbe verificare il caso di Guid.Empty e dare un messaggio più utile.
Ian Ringrose,

4
@Ian Ringrose: non credo che il compilatore dovrebbe avere messaggi specifici per tipo in generale, a dire il vero.
Jon Skeet,

2
L'impostazione di un parametro come predefinito su un nuovo oggetto crea un nuovo oggetto ogni volta che il metodo viene chiamato in PHP; ma crea solo un oggetto per l' intero programma in Python. Davvero, lo considero uno dei pochissimi difetti di progettazione di Python . Sono abbastanza contento che C # (e VB.Net) abbiano evitato questo problema semplicemente vietando nuovi oggetti nei parametri predefiniti ... anche se ci sono momenti in cui questa capacità è davvero piacevole in PHP.
BlueRaja - Danny Pflughoeft,

1
quale potrebbe essere la ragione per cui questa stessa cosa non funzionerebbe nell'azione del controller ASP.NET MVC? Tutti gli altri parametri opzionali funzionano (int, string) ma non funzionano per GUID, dice "Errore del server nell'applicazione '/'. Il dizionario dei parametri contiene una voce nulla per il parametro 'categoryId' di tipo non nullable 'System.Guid '.. "Il codice viene compilato correttamente con entrambe le specifiche (impostazione predefinita (Guid) e con la nuova Guida ()) ma genera questo errore.
mare

@mare: non lo so, ho paura. Un'altra opzione sarebbe quella di utilizzare Nullable<Guid>, potenzialmente.
Jon Skeet,

18

Non puoi usare:

default ( Guid ) ?


1
No. Operator '??' cannot be applied to operands of type 'System.Guid' and 'System.Guid'
ricorsivo il

4
Scusa, non intendevo ?? come operatore ma come punto interrogativo enfatizzato - lo modificherò!
Nick,

9

La risposta accettata non funziona in ASP.NET MVC e causa questo errore di runtime:

[ArgumentException: The parameters dictionary contains a null entry for parameter 'optional' of non-nullable type 'System.Guid' for method 'System.Web.Mvc.ActionResult Problem(System.Guid)' ....

Invece, puoi fare quanto segue:

public void Problem(Guid? optional)
{
    if (optional == null)
    {
        optional = new Guid();
    }
}

Vedo il motivo del voto
negativo

A meno che non si desideri assegnare esplicitamente il parametro "opzionale" con un valore Guid vuoto, penso che questo sia il modo più naturale per definire un parametro facoltativo di tipo Guid.
Gonzalo Méndez,

4

Il compilatore è abbastanza corretto; Guid.Emptynon è una costante di compilazione. Puoi provare a fare un overload del metodo in questo modo:

public void Problem()
{
    Problem(Guid.Empty);
}

Ho detto che non volevo cambiare l'API, il metodo che sto cercando di domare ha oltre 10 parms!
Ian Ringrose,

@Ian Ringrose, anche se sono d'accordo Guid x = default(Guid)come soluzione, ricorda che l'aggiunta di un altro sovraccarico di funzioni non complica l'API più che l'aggiunta di un argomento facoltativo. Questo è davvero ciò che fa comunque un argomento opzionale.
dieci

@tenfour, dovrebbero esserci molti nuovi sovraccarichi di funzioni per fare lo stesso di 10 parametri opzionali!
Ian Ringrose,

Se hai una funzione pubblica che richiede oltre dieci parametri, forse rendere facoltativo un singolo argomento non è davvero una correzione ... Inoltre, guardando indietro alla domanda originale, dici davvero che non vuoi "cambiare il API "(e, come sottolinea Tenfour, la differenza tra un sovraccarico esplicito e un argomento facoltativo è in pratica minima), ma nella domanda dell'elenco dei parametri non si fa menzione di quel tipo di mostro.
un CVn,

In realtà, questa è una risposta perfetta al problema.
PKD,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.