2015-06-19 8 views
6

Sto utilizzando l'operatore ?? per provare e assegnare un oggetto in base alla corrispondenza migliore trovata in un elenco.Catturare quale elemento della mano sinistra nell'operatore a coalescenza nulla ha assegnato correttamente la variabile

ho vari regole di corrispondenza, ma hanno semplificato questo per l'esempio:

objectImTryingToSet = 
MyListOfPotentialMatches.FirstOrDefault(*/lamda checking numerous things*/) ??     //rule1 
MyListOfPotentialMatches.FirstOrDefault(*/lamda checking different numerous things*/) ??  //rule2 
MyListOfPotentialMatches.FirstOrDefault(*/lamda checking again different numerous things*/); //rule3 

Per scopi di debug, vorrei memorizzare una registrazione stringa, che regola era quella che assegnata con successo objectImTryingToSet come ho un bug in cui in uno scenario l'oggetto viene assegnato quando non dovrebbe essere ed è un vero mal di testa che tenta manualmente di setacciare tutte queste regole per scoprire dove si trova l'assegnazione errata.

Così ho praticamente vuole, pseudo:

string ruleThatMatched = null; 

objectImTryingToSet = 
MyListOfPotentialMatches.FirstOrDefault(*/lamda checking numerous things*/) ?? if (objectImTryingToSet != null) { ruleThatMatched = "rule1" }     //rule1 
MyListOfPotentialMatches.FirstOrDefault(*/lamda checking different numerous things*/) ?? if (objectImTryingToSet != null) { ruleThatMatched = "rule2" }  //rule2 
MyListOfPotentialMatches.FirstOrDefault(*/lamda checking again different numerous things*/); if (objectImTryingToSet != null) { ruleThatMatched = "rule3"}  //rule3 

//tried all the rules and still no match 
if (objectImTryingToSet == null) 
{ 
    ruleThatMatched = "no rule managed to find a match"; 
} 

Questo è anche possibile utilizzare l'operatore ???

+9

Perché non si utilizza un 'se ... else'? –

+2

quando si utilizza l'operatore ternario o a coalescenza nulla e si inizia a complicare la procedura, è molto meglio passare a un/se/o interruttore. – Jonesopolis

+4

"Dottore, fa male quando faccio * questo *!" "Smettila." ... Scusa, non ho potuto resistere. :) –

risposta

2

È possibile farlo in questo modo:

var res = 
    MyListOfPotentialMatches.Select(v => new {r=1, v}).FirstOrDefault(/*lamda checking numerous things*/) ?? 
    MyListOfPotentialMatches.Select(v => new {r=2, v}).FirstOrDefault(/*lamda checking different numerous things*/) ?? 
    MyListOfPotentialMatches.Select(v => new {r=3, v}).FirstOrDefault(/*lamda checking again different numerous things*/); 
if (res != null) { 
    var ruleNumber = res.r; 
    objectImTryingToSet = res.v; 
} 

La chiave è Select che coppie fino il risultato con un numero di regola hard-coded.

noti che si potesse fare senza ?? operator, troppo:

var firstChoice = MyListOfPotentialMatches.Select(v => new {r=1, v}).Where(/*lamda checking numerous things*/); 
var secondChoice = MyListOfPotentialMatches.Select(v => new {r=2, v}).Where(/*lamda checking different numerous things*/); 
var thirdChoice = MyListOfPotentialMatches.Select(v => new {r=3, v}).Where(/*lamda checking again different numerous things*/); 
var res = firstChoice.Concat(secondChoice).Concat(thirdChoice).FirstOrDefault(); 
if (res != null) { 
    var ruleNumber = res.r; 
    objectImTryingToSet = res.v; 
} 
+0

quindi è usando i Tipi anonimi per aggiungere una proprietà di sola lettura a v? – JsonStatham

+0

@SelectDistinct Sì, è quello che fa. – dasblinkenlight

+0

Ottiene "Errore Impossibile convertire in modo implicito il tipo 'AnonymousType # 1' in 'MySolution.Core.AddressService.JsonAddressModel'" la prima regola ha questo aspetto per informazioni: Addresses.Select (v => new {r = 1, v}). FirstOrDefault (v => vvpaon.Trim() == exception.AddressLineOne && vvdthorofare.Trim() == exception.AddressLineTwo); – JsonStatham

0

Stai cercando qualcosa di simile?

static void Main(string[] args) 
{ 
    List<int?> intList = new List<int?>() { 3, 4}; 


    Func<int?, bool> rule = null; 

    var value = intList.FirstOrDefault(rule = (i => i == 1)) 
      ?? intList.FirstOrDefault(rule = (i => i == 2)) 
      ?? intList.FirstOrDefault(rule = (i => i == 3)) 
      ?? intList.FirstOrDefault(rule = (i => i == 4)); 
} 

Come nota, questo è solo per esplorare ciò che è possibile fare con la lingua. Non consiglierei di farlo nel codice di produzione. È più difficile da leggere di quanto dovrebbe essere.


Ecco un altro approccio si può prendere

class Program 
{ 
    static void Main(string[] args) 
    { 
     List<int?> intList = new List<int?>() { 3, 4}; 

     List<RuleModel> Rules = new List<RuleModel>(); 

     Rules.Add(new RuleModel{Name = "Rule1", Rule = (i => i == 1)}); 
     Rules.Add(new RuleModel{Name = "Rule2", Rule = (i => i == 2)}); 
     Rules.Add(new RuleModel{Name = "Rule3", Rule = (i => i == 3)}); 
     Rules.Add(new RuleModel{Name = "Rule4", Rule = (i => i == 4)}); 

     int? valueToSet = null; 

     var ruleUsed = Rules.FirstOrDefault(r => (valueToSet = intList.FirstOrDefault(r.Rule)) != null); 
    } 

} 

public class RuleModel 
{ 
    public Func<int?, bool> Rule { get; set; } 
    public string Name { get; set; } 
} 
2

(A cura in modo che sembra più vicino al tuo pseudo codice, ma si dovrà riempire alcuni spazi vuoti, perché io non conosco la tipo del vostro oggetto)

string ruleThatMatched = null; 
Func<string, TypeOfObjectImTryingToSet, TypeOfObjectImTryingToSet> getAndTrackRule = 
    (ruleText, obj) => 
     { 
      ruleThatMatched = ruleText; 
      return obj; 
     }; 


var objectImTryingToSet = 
    getAndTrackRule("rule1", MyListOfPotentialMatches.FirstOrDefault(*/lamda checking numerous things*/)) ?? 
    getAndTrackRule("rule2", MyListOfPotentialMatches.FirstOrDefault(*/lamda checking different numerous things*/)) ?? 
    getAndTrackRule("rule3", MyListOfPotentialMatches.FirstOrDefault(*/lamda checking again different numerous things*/)); 

if (objectImTryingToSet == null) 
{ 
    Console.WriteLine("no rule managed to find a match"); 
} 
else 
{ 
    Console.WriteLine(string.Format("Final value {0} found by applying rule {1}", objectImTryingToSet, ruleThatMatched)); 
} 
0

si dovrebbe creare 3 funzioni di controllo con fuori argomento.

function bool check1(YourObject obj, out string ruleMatched) 
{ 
    ruleMatched = "rule1"; 
    return /* checking numerous things */; 
} 

// same for each checking 

string ruleMatched; 
objectImTryingToSet = 
MyListOfPotentialMatches.FirstOrDefault(x => check1(x, out ruleMatched)) ?? //rule1 
MyListOfPotentialMatches.FirstOrDefault(x => check2(x, out ruleMatched)) ?? //rule2 
MyListOfPotentialMatches.FirstOrDefault(x => check3(x, out ruleMatched)); //rule3 
+0

Quindi il tuo suggerimento che tira ogni regola in un metodo? – JsonStatham

+1

@SelectDistinct sì, aggiungerà più leggibilità e riusabilità. – aleha

2

Ho creato un metodo di estensione personalizzato che racchiude il tipo di logica. Non è bello, ma puoi chiamare questo al posto dello standard FirstOrDefault. È necessario un extra string come parametro out e un altro string come messaggio di debug che si desidera.

Quindi è possibile concatenarli con qualcosa di simile.

string matchedRule; 

var matchedFruit = fruits.GetFirstWithMessage(f => f.Count < 1, out matchedRule, "Out of stock") 
    ?? fruits.GetFirstWithMessage(f => f.Name.Length > 10, out matchedRule, "Long name") 
    ?? fruits.GetFirstWithMessage(f => !f.IsFresh, out matchedRule, "Rotten Fruit") 
    ?? fruits.GetFirstWithMessage(f => f.Count > 24, out matchedRule, "Big group"); 

A demo

+0

@SelectDistinct questo è bello !! –

Problemi correlati