C'è un “opposto” all'operatore nulla coalescenza? (... in qualsiasi lingua?)
-
05-10-2019 - |
Domanda
nulla a coalescenza traduce approssimativamente return x, unless it is null, in which case return y
ho spesso bisogno return null if x is null, otherwise return x.y
posso usare return x == null ? null : x.y;
Non male, ma che null
nel mezzo sempre mi dà fastidio - sembra superfluo. Preferirei qualcosa di simile return x :: x.y;
, dove ciò che segue il ::
solo viene valutato se ciò che lo precede non è null
.
Io vedo questo come quasi un opposto null coalescenza, sorta di misto con un laconico, in linea null-controllo, ma io sono [ quasi ] certo che non c'è tale operatore in C #.
Ci sono altre lingue che hanno un tale operatore? Se è così, come si chiama?
(so che posso scrivere un metodo per esso in C #;. Io uso return NullOrValue.of(x, () => x.y);
, ma se avete qualcosa di meglio, mi piacerebbe vedere che troppo)
Soluzione
C'è il nullo-safe operatore dereferenziazione (?.) In Groovy ... Penso che sia quello che stai dopo.
(E 'anche chiamata la navigazione sicura dell'operatore . )
Ad esempio:
homePostcode = person?.homeAddress?.postcode
Questo darà null se person
, person.homeAddress
o person.homeAddress.postcode
è nullo.
(Questo è ora disponibili in C # 6.0 ma non in precedenza le versioni)
Altri suggerimenti
Abbiamo preso in considerazione l'aggiunta di?. a C # 4. Non aveva il taglio; si tratta di un "bello avere" caratteristica, non un "Gotta have" caratteristica. Noi prenderemo in considerazione di nuovo per le versioni future ipotetiche del linguaggio, ma non mi trattengo il respiro in attesa, se fossi in te. Non è probabile che per ottenere più importante col passare del tempo. : -)
Se hai un particolare tipo di corto circuito logica booleana, si può fare questo (ad esempio javascript):
return x && x.y;
Se x
è nullo, allora non valutare x.y
.
Mi sembrava giusto per aggiungere questo come una risposta.
Credo che la ragione per la quale non v'è nulla di simile in C # è perché, a differenza l'operatore coalescenza (che è valido solo per i tipi di riferimento), l'operazione inversa potrebbe produrre sia un tipo di riferimento o di valore (cioè class x
con gli int y
- quindi sarebbe purtroppo inutilizzabile in molte situazioni.
Non sto dicendo, però, che non mi piacerebbe vederlo!
Una possibile soluzione a questo problema sarebbe per l'operatore solleva automaticamente un tipo di valore espressione a destra-lato ad una annullabile. Ma allora si ha il problema che x.y
dove y è un int effettivamente restituito un int?
che sarebbe un dolore.
Un altro, probabilmente migliore soluzione sarebbe per l'operatore per restituire il valore predefinito (cioè null o zero) per il tipo sul lato destro se l'espressione a sinistra è nullo. Ma poi avete problemi che contraddistinguono scenari in cui un / null zero è stato effettivamente letto da x.y
o se sia stata fornita dall'operatore di sicurezza di accesso.
Delphi ha:. (. Anziché) operatore, che è nullo-safe
che stavano pensando di aggiungere una?. all'operatore di C # 4.0 per fare lo stesso, ma che ha ottenuto il blocco di modulazione.
Nel frattempo, c'è IfNotNull () quale tipo di graffi che prurito. E 'certamente più grande di?. o:., ma non consentono di comporre una catena di operazioni che non Hork un NullReferenceException a voi se uno dei membri è null
In Haskell, è possibile utilizzare l'operatore >>
:
-
Nothing >> Nothing
ISNothing
-
Nothing >> Just 1
ISNothing
-
Just 2 >> Nothing
ISNothing
-
Just 2 >> Just 1
ISJust 1
Haskell ha fmap
, che in questo caso credo sia toData.Maybe.map
equivalente. Haskell è puramente funzionale, così che cosa state cercando sarebbe
fmap select_y x
Se x
è Nothing
, restituisce Nothing
. Se x
è Just object
, restituisce Just (select_y object)
. Non bella come notazione del punto, ma dato che si tratta di un linguaggio funzionale, gli stili sono diversi.
PowerShell vi lasciate riferimento proprietà (ma non i metodi di chiamata) su un riferimento null e restituirà null se l'istanza è null. Lo si può fare a qualsiasi profondità. Avevo sperato che C # caratteristica dinamica di 4 sosterrebbe questo, ma non è così.
$x = $null
$result = $x.y # $result is null
$x = New-Object PSObject
$x | Add-Member NoteProperty y 'test'
$result = $x.y # $result is 'test'
Non è bello, ma si potrebbe aggiungere un metodo di estensione che funzionerà il modo in cui si descrive.
public static TResult SafeGet<T, TResult>(this T obj, Func<T, TResult> selector) {
if (obj == null) { return default(TResult); }
else { return selector(obj); }
}
var myClass = new MyClass();
var result = myClass.SafeGet(x=>x.SomeProp);
public class ok<T> {
T s;
public static implicit operator ok<T>(T s) { return new ok<T> { s = s }; }
public static implicit operator T(ok<T> _) { return _.s; }
public static bool operator true(ok<T> _) { return _.s != null; }
public static bool operator false(ok<T> _) { return _.s == null; }
public static ok<T> operator &(ok<T> x, ok<T> y) { return y; }
}
ho spesso bisogno questa logica per le stringhe:
using ok = ok<string>;
...
string bob = null;
string joe = "joe";
string name = (ok)bob && bob.ToUpper(); // name == null, no error thrown
string boss = (ok)joe && joe.ToUpper(); // boss == "JOE"
Creare un'istanza statica del vostro posto di classe con tutti i valori di default giusti per i membri.
Ad esempio:
z = new Thingy { y=null };
allora al posto del tuo
return x != null ? x.y : null;
è possibile scrivere
return (x ?? z).y;
Questo è stato aggiunto in C # vNext (Roslyn alimentato C #, uscite con Visual Studio 2014).
Si chiama Null propagazione ed è elencato qui come completa. https://roslyn.codeplex.com/wikipage?title=Language%20Feature%20Status
E 'anche elencati qui il più completo: https://visualstudio.uservoice.com / forum / 121579-visual-studio / suggerimenti / 3.990.187-add-operatore-to-c
Il cosiddetto "operatore null-condizionale" è stato introdotto in C # 6.0 e in Visual Basic 14.
In molte situazioni può essere utilizzato come l'esatto opposto dell'operatore null coalescenza:
int? length = customers?.Length; // null if customers is null
Customer first = customers?[0]; // null if customers is null
int? count = customers?[0]?.Orders?.Count(); // null if customers, the first customer, or Orders is null