LINQ是否有类似Match的语法?

本文关键字:语法 Match 是否 LINQ | 更新日期: 2023-09-27 18:17:43

这是一个我试图优雅地解决的案例。假设我有一个可枚举对象(它可能是一个相当大的可枚举对象,我宁愿只枚举一次)。如果序列中返回的对象符合特定的操作条件,那么我想运行特定的操作。

在函数式语言中,我可以设置匹配序列,当找到匹配时执行该序列。我想在c#中实现类似的功能。如果可能的话使用LINQ

我最接近的是使用策略模式和一个简单的规则引擎,按顺序调用每个注册的策略,直到找到匹配。有没有更简单的方法?

我想做的是。

myEnum.Match((item)=>item.MatchesCondition, (item)=>ExecuteFunction(item))
  .Match((item)=>item.MatchesSomeOtherCondition, (item)=>ExecuteSomeOtherFunction(item));

LINQ是否有类似Match的语法?

您可以创建一个扩展方法Match:

public static class Extensions
{
    public static IEnumerable<T> Match<T>(this IEnumerable<T> items, Func<T, bool> condition, Action<T> action)
    {
        foreach (T item in items)
        {
            if (condition(item))
            {
                action(item)
            }
            else
            {
                yield return item;
            }
        }
    }
}

这将循环遍历items和:

  • 如果符合条件,执行action
  • 否则,通过迭代器
  • 返回项。

你可以使用现有的LINQ功能,像这样:

SomeList.Where(item => item.Equals(item));

如果你不想过滤一个精确匹配,但要过滤一个"包含",你可以使用这个表达式:

SomeList.Where(item => item.Contains(item));

您可以创建一个包含条件和关联操作的Dictionary,允许您继续遍历一系列条件,直到找到匹配,然后调用关联的操作。

void Main()
{
    var collection = new List<string> { "One", "Two" };
    var dict = new Dictionary<Func<string, bool>, Action<string>>
    {
        { ConditionOne, ActionOne },
        { ConditionTwo, ActionTwo },
    };
    Match(collection, dict);
}
public void Match<T>(IEnumerable<T> collection, 
    Dictionary<Func<T, bool>, Action<T>> matchMap)
{
    var wasMatched = false;
    foreach (var item in collection)
    {
        if (wasMatched) break;
        foreach (var pair in matchMap)
        {
            if (wasMatched) break;
            if (pair.Key(item))
            {
                pair.Value(item);
                wasMatched = true;
            }   
        }
    }
}
public bool ConditionOne<T>(T item)
{
    return false;
}
public void ActionOne<T>(T item)
{
    Console.WriteLine(item);
}
public bool ConditionTwo<T>(T item)
{
    return true;
}
public void ActionTwo<T>(T item)
{
    Console.WriteLine(item);
}