捕获null-coalescing运算符中的左手项成功分配变量

时间:2015-06-19 14:24:03

标签: c#

我使用??运算符尝试根据列表中找到的最佳匹配项来分配对象。

我有各种匹配规则,但为此示例简化了这一点:

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

出于调试目的,我想存储一个字符串,记录哪个规则是成功分配objectImTryingToSet的规则,因为我在一个场景中有一个bug wherby,当它不应该被分配时并且手动地试图筛选所有这些规则以找出错误分配所在的位置是一件非常令人头疼的事。

所以我基本上想要,伪:

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

使用??运算符可以实现这一点吗?

5 个答案:

答案 0 :(得分:2)

(编辑使其看起来更接近您的伪代码,但您必须填写一些空白,因为我不知道您的对象的类型)

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

答案 1 :(得分:2)

我制作了一个自定义的扩展方法,它包含了你的逻辑。它并不漂亮,但您可以将其称为标准FirstOrDefault而不是标准string。它需要额外的out作为string参数,而另一个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; } 作为您想要的调试消息。

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

然后你可以用这样的东西将它们连在一起。

    private void StartProcess(string path)
    {
        ProcessStartInfo StartInformation = new ProcessStartInfo();

        StartInformation.FileName = path;

        Process process = Process.Start(StartInformation);

        process.EnableRaisingEvents = true;
    }
    private void ClickFunc(object sender, RoutedEventArgs e)
    {
        if (File.Exists(ProgramPath))
        {
            StartProcess(ProgramPath);
        }
        else
        {
            MessageBox.Show("Specified path does not exist, please try again.", "Bad File Path Error", MessageBoxButton.OK);
        }
    }

A demo

答案 2 :(得分:2)

你可以这样做:

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

密钥是Select,它将结果与硬编码的规则编号配对。

请注意,您也可以在没有??运算符的情况下执行此操作:

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

答案 3 :(得分:0)

你在找这样的东西吗?

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

请注意,这仅用于探索您可以使用该语言执行的操作。我不建议在生产代码中实际执行此操作。这比阅读更难阅读。

这是您可以采取的另一种方法

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

答案 4 :(得分:0)

您应该使用 out 参数创建3个检查功能。

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