C# 从一组枚举值中选择

C# 从一组枚举值中选择,c#,linq,enums,lambda,C#,Linq,Enums,Lambda,我有一个包含一个枚举属性列表的项集合。 原始属性看起来像 public class Content { List<State> States {get; set;} } 如何使用Linq或Lambda实现这一点?您不需要Linq。我不认为 if(item.States.Contains(State.Important) && item.States.Contains(State.Updated)) string toProcess = "Do"; 你不

我有一个包含一个枚举属性列表的项集合。 原始属性看起来像

public class Content {
    List<State> States {get; set;}
}

如何使用Linq或Lambda实现这一点?

您不需要Linq。我不认为

if(item.States.Contains(State.Important) && item.States.Contains(State.Updated))
  string toProcess = "Do";

你不需要林克。我不认为

if(item.States.Contains(State.Important) && item.States.Contains(State.Updated))
  string toProcess = "Do";

如果必须使用Linq:

if (item.States.Any(state => state == State.Important) && item.States.Any(state => state == State.Updated))
否则,只需使用@ElRonnoco所说的内容

然而,如果你的州是2的幂,那么这个答案将略有不同

这种方法的问题在于,如果两种状态都没有设置,它会在集合上完全迭代两次。如果这种情况经常发生,它将比可能的要慢

您可以在不使用linq的情况下在一次过程中解决它,如下所示:

bool isUpdated = false;
bool isImportant = false;

foreach (var state in item.States)
{
    if (state == State.Important)
        isImportant = true;
    else if (state == State.Updated)
        isUpdated = true;

    if (isImportant && isUpdated)
        break;
}

if (isImportant && isUpdated)
{
    // ...
}
这不太可能成为一个问题,除非您有非常大的列表,而这些列表通常没有设置任何一个目标状态,因此您可能最好还是使用El Ronnoco的解决方案

如果有很多状态需要处理,可以通过编写如下扩展方法来简化:

public static class EnumerableExt
{
    public static bool AllPredicatesTrueOverall<T>(this IEnumerable<T> self, params Predicate<T>[] predicates)
    {
        bool[] results = new bool[predicates.Length];

        foreach (var item in self)
        {
            for (int i = 0; i < predicates.Length; ++i)
                if (predicates[i](item))
                    results[i] = true;

            if (results.All(state => state))
                return true;
        }

        return false;
    }
下面是一些使用它的示例代码:

enum State
{
    Unknown,
    Important,
    Updated,
    Deleted,
    Other
}

void run()
{
    IEnumerable<State> test1 = new[]
    {
        State.Important, 
        State.Updated, 
        State.Other, 
        State.Unknown
    };

    if (test1.AllPredicatesTrueOverall(s => s == State.Important, s => s == State.Updated))
        Console.WriteLine("test1 passes.");
    else
        Console.WriteLine("test1 fails.");

    IEnumerable<State> test2 = new[]
    {
        State.Important, 
        State.Other, 
        State.Other, 
        State.Unknown
    };

    if (test2.AllPredicatesTrueOverall(s => s == State.Important, s => s == State.Updated))
        Console.WriteLine("test2 passes.");
    else
        Console.WriteLine("test2 fails.");

    // And to show how you can use any number of predicates:

    bool result = test1.AllPredicatesTrueOverall
    (
        state => state == State.Important,
        state => state == State.Updated,
        state => state == State.Other,
        state => state == State.Deleted
    );
}
您可以轻松指定更多状态:

if (item.States.AllStatesSet(State.Important, State.Updated, State.Deleted))

如果必须使用Linq:

if (item.States.Any(state => state == State.Important) && item.States.Any(state => state == State.Updated))
否则,只需使用@ElRonnoco所说的内容

然而,如果你的州是2的幂,那么这个答案将略有不同

这种方法的问题在于,如果两种状态都没有设置,它会在集合上完全迭代两次。如果这种情况经常发生,它将比可能的要慢

您可以在不使用linq的情况下在一次过程中解决它,如下所示:

bool isUpdated = false;
bool isImportant = false;

foreach (var state in item.States)
{
    if (state == State.Important)
        isImportant = true;
    else if (state == State.Updated)
        isUpdated = true;

    if (isImportant && isUpdated)
        break;
}

if (isImportant && isUpdated)
{
    // ...
}
这不太可能成为一个问题,除非您有非常大的列表,而这些列表通常没有设置任何一个目标状态,因此您可能最好还是使用El Ronnoco的解决方案

如果有很多状态需要处理,可以通过编写如下扩展方法来简化:

public static class EnumerableExt
{
    public static bool AllPredicatesTrueOverall<T>(this IEnumerable<T> self, params Predicate<T>[] predicates)
    {
        bool[] results = new bool[predicates.Length];

        foreach (var item in self)
        {
            for (int i = 0; i < predicates.Length; ++i)
                if (predicates[i](item))
                    results[i] = true;

            if (results.All(state => state))
                return true;
        }

        return false;
    }
下面是一些使用它的示例代码:

enum State
{
    Unknown,
    Important,
    Updated,
    Deleted,
    Other
}

void run()
{
    IEnumerable<State> test1 = new[]
    {
        State.Important, 
        State.Updated, 
        State.Other, 
        State.Unknown
    };

    if (test1.AllPredicatesTrueOverall(s => s == State.Important, s => s == State.Updated))
        Console.WriteLine("test1 passes.");
    else
        Console.WriteLine("test1 fails.");

    IEnumerable<State> test2 = new[]
    {
        State.Important, 
        State.Other, 
        State.Other, 
        State.Unknown
    };

    if (test2.AllPredicatesTrueOverall(s => s == State.Important, s => s == State.Updated))
        Console.WriteLine("test2 passes.");
    else
        Console.WriteLine("test2 fails.");

    // And to show how you can use any number of predicates:

    bool result = test1.AllPredicatesTrueOverall
    (
        state => state == State.Important,
        state => state == State.Updated,
        state => state == State.Other,
        state => state == State.Deleted
    );
}
您可以轻松指定更多状态:

if (item.States.AllStatesSet(State.Important, State.Updated, State.Deleted))
列表有一个Contains方法,所以您的代码

if(item.States.Contains(State.Important) && item.States.Contains(State.Updated))
    string toProcess = "Do";
我看不出在这里使用Linq或lambda表达式有什么真正的好处…

列表有一个Contains方法,所以您的代码应该是

if(item.States.Contains(State.Important) && item.States.Contains(State.Updated))
    string toProcess = "Do";
我认为在这里使用Linq或lambda表达式没有什么真正的好处…

您可以选择

!(new List<States>{State.Important, State.Updated}.Except(item.States).Any());
它不是很短,但是如果你有大量的州要检查,它会更容易

只要您想检查项目是否具有所需的所有状态,您只需将新状态添加到第一个列表中。

您可以使用

!(new List<States>{State.Important, State.Updated}.Except(item.States).Any());
它不是很短,但是如果你有大量的州要检查,它会更容易


只要您想检查该项是否具有所需的所有状态,您只需将新状态添加到第一个列表中。

以下某种实现

Content obj = new Content();
obj.States = SomeMethod(); 

if(obj.States.Any(h => h == State.Important) && obj.States.Any(h => h == State.Updated))
{
   string toProcess = "Do";
}

某种形式的后续实现

Content obj = new Content();
obj.States = SomeMethod(); 

if(obj.States.Any(h => h == State.Important) && obj.States.Any(h => h == State.Updated))
{
   string toProcess = "Do";
}
试试这个


试试这个

也许你可以考虑使用你的枚举作为一组标志,也就是说你可以组合多个状态而没有列表:

[Flags]
public enum State
{
    Important = 1,
    Updated = 2,
    Deleted = 4,
    XXX = 8
    ....
}

public class Content
{
    public State MyState { get; set; }
}

if ((myContent.MyState & State.Important) == State.Important
    && (myContent.MyState & State.Updated) == State.Updated)
{
    // Important AND updated
}

也许你可以考虑使用EnUM作为一组标志,也就是说,你可以组合多个状态而没有列表:

[Flags]
public enum State
{
    Important = 1,
    Updated = 2,
    Deleted = 4,
    XXX = 8
    ....
}

public class Content
{
    public State MyState { get; set; }
}

if ((myContent.MyState & State.Important) == State.Important
    && (myContent.MyState & State.Updated) == State.Updated)
{
    // Important AND updated
}

+提到旗帜——这听起来可能是一个很好的方法。与其有一个状态列表,不如有一个状态变量本身可以作为列表…@PaoloTedesco道歉-我误解了原来的问题。然而,我认为我的阅读最终是正确的!用这种方式编写15+个状态的组合听起来不是一个好方法。我有很多基于状态组合的if条件。有些甚至是动态的,作为另一个列表出现,这就是为什么寻找Linq或Lambda@Nirav我添加了更多的例子。+1用于提及旗帜-这听起来可能是一个很好的OP方法。与其有一个状态列表,不如有一个状态变量本身可以作为列表…@PaoloTedesco道歉-我误解了原来的问题。然而,我认为我的阅读最终是正确的!用这种方式编写15+个状态的组合听起来不是一个好方法。我有很多基于状态组合的if条件。有些甚至是动态的,作为另一个列表出现,这就是为什么寻找Linq或Lambda@Nirav我添加了更多的例子。我不知道这件事是否是故意的,但请不要改变它:是的,我担心这是故意的。我不能只是不小心把那种喜剧的金块扔了!!我不知道这件事是否是故意的,但请不要改变它:是的,恐怕是故意的。我不能只是不小心把那种喜剧的金块扔了!!这只是If条件的一个例子。我知道。但以Has为例。我有很多基于状态组合的if条件。有些甚至是动态的,作为另一个列表出现,这就是为什么寻找Linq或LambdaI没有看到这有什么问题。只需为每个条件创建一个状态列表,并在此应用任何答案即可。你可以扩展我的答案,例如,轻松处理许多案例。这只是If条件的一个例子。我知道。但以Has为例。我有
许多if条件基于状态的组合。有些甚至是动态的,作为另一个列表出现,这就是为什么寻找Linq或LambdaI没有看到这有什么问题。只需为每个条件创建一个状态列表,并在此应用任何答案即可。你可以扩展我的回答,例如,轻松处理许多案件。