Domanda

Ho un certo numero di metodi di fare successivo:

var result = command.ExecuteScalar() as Int32?;
if(result.HasValue)
{
   return result.Value;
}
else
{
   throw new Exception(); // just an example, in my code I throw my own exception
}

Vorrei poter usare operatore ?? in questo modo:

return command.ExecuteScalar() as Int32? ?? throw new Exception();

ma genera un errore di compilazione.

E 'possibile riscrivere il mio codice o c'è un solo modo per farlo?

È stato utile?

Soluzione

Per C # 7

In C # 7, throw diventa espressione, quindi è bene utilizzare esattamente il codice descritto nella questione.

per C # 6 e versioni precedenti

Non si può fare che direttamente in C # 6 e precedenti - secondo operando di ?? ha bisogno di essere un'espressione, non una dichiarazione tiro.

Ci sono poche alternative se siete veramente solo cercando di trovare un'opzione che è conciso:

Si potrebbe scrivere:

public static T ThrowException<T>()
{
    throw new Exception(); // Could pass this in
}

E poi:

return command.ExecuteScalar() as int? ?? ThrowException<int?>();

I davvero non è consigliabile lo fai però ... è abbastanza orribile e unidiomatic.

Come su un metodo di estensione:

public static T ThrowIfNull(this T value)
{
    if (value == null)
    {
        throw new Exception(); // Use a better exception of course
    }
    return value;
}

Quindi:

return (command.ExecuteScalar() as int?).ThrowIfNull();

Ancora un'altra alternativa (ancora un metodo di estensione):

public static T? CastOrThrow<T>(this object x) 
    where T : struct
{
    T? ret = x as T?;
    if (ret == null)
    {
        throw new Exception(); // Again, get a better exception
    }
    return ret;
}

chiamata con:

return command.ExecuteScalar().CastOrThrow<int>();

E 'un po' brutto, perché non è possibile specificare int? come argomento di tipo ...

Altri suggerimenti

Come si è detto, non si può fare questo con l'?? operatore (beh, non senza alcune contorsioni che non sembrano adattarsi con il fine di renderlo più pulito).

Quando vedo questo modello emergente penso subito di Esecuzioni . Originario mondo C ++ trasferiscono a C # abbastanza bene, anche se sono senza dubbio meno importante la maggior parte del tempo.

L'idea è che si prende qualcosa del tipo:

if( condition )
{
  throw Exception;
}

e lo converte in:

Enforce<Exception>( condition );

(si può semplificare ulteriormente adempiendo il tipo di eccezione).

Prendendo ulteriormente è possibile scrivere un insieme di metodi in stile Nunit per le diverse condizioni assegni, per esempio;.

Enforce<Exception>.NotNull( obj );
Enforce<Exception>.Equal( actual, expected );
Enforce<Exception>.NotEqual( actual, expected );

ecc.

O, meglio ancora, fornendo un Lamba aspettativa:

Enforce<Exception>( actual, expectation );

La cosa veramente pulito è che, una volta che hai fatto, è possibile restituire il reale param e far rispettare in linea :

return Enforce( command.ExecuteScalar() as Int32?, (o) => o.HasValue ).Value;

... e questo sembra essere più vicino a quello che stai dopo.

Ho bussato a un'implementazione di questo prima. Ci sono un paio di piccoli particolari, come come si crea genericamente un oggetto eccezione che prende argomenti - alcune scelte là (ho scelto di riflessione, al momento, ma passando una fabbrica come un parametro supplementare potrebbe essere ancora meglio). Ma in generale è tutto piuttosto semplice e può davvero ripulire un sacco di codice.

E 'sulla mia lista di cose da fare per battere fino un'implementazione open source.

Se si desidera solo un'eccezione quando il valore restituito non è un Int32 quindi fare questo:

return (int)command.ExecuteScalar();

Se si vuole buttare il proprio eccezione personalizzata allora probabilmente sarei fare qualcosa di simile, invece:

int? result = command.ExecuteScalar() as int?;
if (result == null) throw new YourCustomException();
return result.Value;

Non sta andando ad essere in grado di generare un'eccezione sul lato destro dell'operatore null coalescenza. La ragione di questo è che che il lato destro dell'operatore deve essere un'espressione, non un comunicato.

L'operatore null coalescenza funziona in questo modo: se il valore sinistra dell'operatore è nullo, restituirlo; in caso contrario, restituire ciò che è sulla destra dell'operatore. La parola chiave throw non restituisce un valore; pertanto, non può essere utilizzato sul lato destro dell'operatore.

Il motivo non si può fare:

return command.ExecuteScalar() as Int32? ?? throw new Exception();

È perché un'eccezione è una dichiarazione, non è un'espressione.

Se stai solo cercando di accorciare il codice un po ', forse questo:

var result = command.ExecuteScalar() as Int32?;
if(result.HasValue) return result;
throw new Exception();

Non c'è bisogno per l'altro.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top