Capturing that the left hand element in the zero coalescence operator has successfully assigned a variable

Am I using the operator ?? to try to assign an object based on the best match found in the list.

I have various matching rules, but simplified this for an example:

 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 

For debugging purposes, I would like to save the record in a line, which rule was the one that successfully assigned objectImTryingToSet , since I have an error when in one script an object is assigned, when it should not be, and its real headache manually tries to sift all of these rules to find out where the wrong assignment is located.

So I basically want a 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"; } 

Is this possible with the operator ?? ?

+6
source share
5 answers

You can do it as follows:

 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; } 

A Select key that connects the result to a hard-coded rule number.

Please note that you can do this without an operator ?? :

 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; } 
+2
source

(Edited so that it looks closer to your pseudo-code, but you will need to fill in some spaces because I don't know the type of your object)

 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)); } 
+2
source

I made a special extension method that completes your logic. It is not very, but you can name it instead of standard FirstOrDefault . It takes an extra string as the out parameter, and another string as the required debug message.

 public static T GetFirstWithMessage<T>(this IEnumerable<T> collection, Func<T, bool> matchFunc, out string outputString, string message) { var match = collection.FirstOrDefault(matchFunc); outputString = match == null ? null : message; return match; } 

You can then associate them with something like this.

 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"); 

Demo

+2
source

Are you looking for something like this?

 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)); } 

As a side note, this is only for learning what you can do with the language. I would not recommend doing this in production code. It is harder to read than necessary.


Here is another approach you can take

 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; } } 
0
source

you must create 3 control functions with an out argument.

 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
source

Source: https://habr.com/ru/post/989411/


All Articles