我有一个枚举属性列表的项目集合。 原始属性看起来像
public class Content {
List<State> States {get; set;}
}
其中'State'是enum,有近15个选项。
在迭代Content对象的集合时,我想检查一下States States属性是否有State.Important和State.Updated等特定值存在于States中,并从中设置另一个字符串。
类似
if(item.States.Has(State.Important) && item.States.Has(State.Updated))
string toProcess = "Do";
如何使用Linq或Lambda执行此操作?
答案 0 :(得分:4)
如果您必须使用Linq:
,这应该有效if (item.States.Any(state => state == State.Important) && item.States.Any(state => state == State.Updated))
否则只需使用像@ElRonnoco那样的Contains()
。
(但是如果你的州是旗帜(权力为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;
}
我为此找到一个名字有些困难。如果对于每个谓词,序列中至少有一个谓词为真的项,它将返回true
。但是对于方法名称来说这有点长......;)
然后你的例子将成为:
if (item.States.AllPredicatesTrueOverall(s => s == State.Important, s => s == State.Updated))
以下是一些使用它的示例代码:
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
);
}
但也许最简单的方法是为IEnumerable<State>
编写一个扩展方法(如果你只需要担心一个状态枚举):
public static class EnumerableStateExt
{
public static bool AllStatesSet(this IEnumerable<State> self, params State[] states)
{
bool[] results = new bool[states.Length];
foreach (var item in self)
{
for (int i = 0; i < states.Length; ++i)
if (item == states[i])
results[i] = true;
if (results.All(state => state))
return true;
}
return false;
}
}
然后您的原始代码将变为:
if (item.States.AllStatesSet(State.Important, State.Updated))
您可以轻松指定更多状态:
if (item.States.AllStatesSet(State.Important, State.Updated, State.Deleted))
答案 1 :(得分:2)
你不需要Linq。我不瘦身
if(item.States.Contains(State.Important) && item.States.Contains(State.Updated))
string toProcess = "Do";
答案 2 :(得分:1)
列表有一个Contains
方法,因此您的代码将是
if(item.States.Contains(State.Important) && item.States.Contains(State.Updated))
string toProcess = "Do";
我认为在这里使用Linq或lambda表达没有任何实际好处......
答案 3 :(得分:0)
你可以选择
!(new List<States>{State.Important, State.Updated}.Except(item.States).Any());
它不是真的更短,但如果你有大量的状态要检查它会更容易。
只要您想检查项目是否具有所需的所有状态,您只需将新状态添加到第一个列表即可。
答案 4 :(得分:0)
某种以下实施
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";
}
答案 5 :(得分:0)
var res = (from items in item
where items.States.Has(State.Important) && items.States.Has(State.Updated)
select new { NewProcess = "Do" }).ToList();
foreach (var result in res)
{
string result = result.NewProcess
}
试试这个
答案 6 :(得分:0)
也许你可以考虑将你的枚举用作一组标志,即你可以在没有列表的情况下组合多个状态:
[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
}