C# 检查列表通过将属性与枚举进行比较,顺序正确



我有一个要返回的对象列表,我需要检查它们是否按正确的顺序由其中一个属性(如枚举中定义)返回。

举一个更好的例子。假设我有一个 List(),其中包含以下内容

{ Name: "name1", Action: SomeAction.Read, Value: someValue },
{ Name: "name2", Action: SomeAction.Create, Value: someValue },
{ Name: "name3", Action: SomeAction.Update, Value: someValue },
{ Name: "name4", Action: SomeAction.Delete, Value: someValue },
{ Name: "name5", Action: SomeAction.Archive, Value: someValue }

枚举包含以下内容:

public enum SomeAction
{
Read,
Create,
Update,
Delete,
Download,
Archive,
Restore
}

有没有办法与枚举进行比较,以检查列表是否按 Action 属性正确排序?

需要注意的一点是,列表可能不包含具有枚举中定义的所有操作的属性的对象,因此列表可能只有读/写/删除属性等。

枚举可以分配一个整数值(有些人可能称之为"序数")。可以通过强制转换来获取此整数值。

int valueOfEnum = (int)SomeEnum.SomeEnumValue;

在您的情况下,您尚未分配整数值,这很好。如果不分配它们,则 C# 将自动为你分配它们。它们从0开始,然后从那里递增。

下面是有关使用这些枚举"值"的 MSDN 文档。

可以按希望出现的顺序将项放入enum SomeAction定义中,并让 C# 自动分配值。这可能是您需要做的全部工作。

您还可以为每个值分配值,以指定您喜欢的顺序。如果要以不同的顺序声明它们,这会有所帮助。

public enum SomeAction
{
Read = 1,
Create = 3,
Update = 2, // Update should come before Create in my list, so I give it a lower value
// ...

如果要按组对操作进行排序,可以使用此手动分配技术来分配重复值(可能是Archive = 1Update = 1)。

现在,您已经有了比较列表中项目的基础,有几种方法可以确保它们按顺序排列:

只需排序即可

确保约束的一个好方法是自己完成工作。排序,它将被排序:)

仅当您的排序函数产生稳定的排序时,这才有效。MSDN 上的文档说OrderBy进行稳定的排序,所以如果你使用这种方法就可以了。

仅当您有能力重新排序列表中的项目时,它也将起作用。从您的操作的定义(每个操作都依赖于先前状态的操作列表)来看,我不确定这是真的。您可能需要选择其他方法来检查订单。

var sortedList = yourList.OrderBy(item => (int)item.Action).ToList();

将列表与自身的排序版本进行比较

如果您正在执行错误检查,但不想更正错误,这将非常有用。

此方法不会更改列表,因此对于您正在查看的操作类型可能是安全的。

var sortedList = yourList.OrderBy(item => (int)item.Action);
bool isSorted = Enumerable.SequenceEqual(yourList, sortedList);

手动编写比较算法

如果您需要严格控制内存分配和 CPU 使用率,这可能很有用。

你可能不需要这种级别的控制,除非你的列表真的很大,或者你正处于高性能代码的紧密循环(如视频游戏绘制循环)的中间。即使在这些情况下,如果可能的话,您也可能需要考虑重构代码,以便此检查不会处于紧密循环的中间。

关于为什么我使用for而不是foreach,请参阅 - 在 .NET 中,哪个循环运行得更快,"for"还是"foreach"?

// Note that you have to build a custom type for your list items to keep high performance,
// or write this inline instead of as a function, to avoid the perf hit of IList<dynamic>
bool IsMySpecificListTypeSorted(List<MyCustomListItemType> theList) {
int previousOrdinal = -1;
// Not using foreach because it is "8x slower" in tests
// and you're micro-optimizing in this scenario
for(int index = 0; index < theList.Count; ++index) {
var item = theList[index];
var currentOrdinal = (int)item.Action;
if(currentOrdinal < previousOrdinal) {
return false;
}
previousOrdinal = currentOrdinal;
}
return true;
}

如果我理解正确,您想按枚举中的项目顺序排序,对吗?

如果确实如此,那么您可能知道枚举项具有 int 值。 考虑到这一点,您可以像这样订购:

List<dynamic> demo = new List<dynamic>();
demo.Add(new { Name = "name1", Action = SomeAction.Read, Value = "someValue" });
demo.Add(new { Name = "name1", Action = SomeAction.Restore, Value = "someValue" });
demo.Add(new { Name = "name1", Action = SomeAction.Update, Value = "someValue" });
demo = demo.OrderBy(e => (int)e.Action).ToList();

编辑我同意这很可能不是正确的方法。基于枚举排序。OP 可能希望完全改变方法。

我会这样做,使用 linq 扩展Zip

var inorder= Enum.GetNames(typeof(SomeAction))
.Zip(array,(x,y) => y.Contains(x))      // change this condition to get uniqueness. 
.All(x=>x);

检查此Demo

如果您有正确排序SomeAction的项目,那么只需排序和比较:

List<MyType> list = ...
var orderedRight = list
.OrderBy(item => (int) (item.Action))
.Select(item => item.Action);
boolean inCorrectOrder = list.SequenceEqual(orderedRight
.Select(item => item.Action));

如果要使用任意顺序,请添加映射

Dictionary<SomeAction, int> map = new Dictionary<SomeAction, int>() {
{SomeAction.Read, 2},
{SomeAction.Create, 1}, // Create should be 1st
{SomeAction.Update, 2}, // Read and Update considered interchangeable
...
{SomeAction.Create, 15},
};
...
var orderedRight = list
.OrderBy(item => map[item.Action])
.Select(item => item.Action);
boolean inCorrectOrder = list.SequenceEqual(orderedRight
.Select(item => item.Action));

您可以为枚举分配特定值,然后实现 IComparable,如下所示

public class TestObj : IComparable<TestObj>
{
public string Name { get; set; }
public SomeAction Action { get; set; }
public string Value { get; set; }
public TestObj(string name, SomeAction action, string value)
{
Name = name;
Action = action;
Value = value;
}
public enum SomeAction
{
Read = 0,
Create = 1,
Update = 2,
Delete = 3,
Download = 4,
Archive = 5,
Restore = 6
}
public override string ToString()
{
return string.Format("Name: {0}, Action: {1}, Value: {2}", Name, Action.ToString(), Value);
}
public int CompareTo(TestObj obj)
{
return this.Action.CompareTo(obj.Action);
}
}

按如下方式创建列表并按正确顺序排序、输出

List<TestObj> objs = new List<TestObj>();
objs.Add(new TestObj("1", Form1.SomeAction.Delete));
objs.Add(new TestObj("2", Form1.SomeAction.Archive));
objs.Add(new TestObj("3", Form1.SomeAction.Read));
objs.Add(new TestObj("4", Form1.SomeAction.Update));
objs.Add(new TestObj("5", Form1.SomeAction.Create));
objs.Sort();
foreach (var item in objs)
{
Console.WriteLine(item.ToString());
}

假设"items"是项目的数组,请使用以下方法:

Enumerable.Range(1, items.Length - 1)
.All(i => (int)(items[i - 1].Action) < (int)(items[i].Action));

您可以使用简单的 for 循环来检查是否满足条件。

var enums = Enum.GetValues(typeof(SomeAction)).Cast<SomeAction>();
for (int i = 0; i < list.Count; i++)
{
var listAction = list.ElementAt(i).Action;
var indexEnumAction = (SomeAction)i;
Console.WriteLine("{0} == {1} ? {2}", listAction, indexEnumAction, listAction == indexEnumAction);
}

输出:

Read == Read ? True
Create == Create ? True
Update == Update ? True
Delete == Delete ? True
Archive == Download ? False

最快的方法:

var enums = Enum.GetValues(typeof(SomeAction)).Cast<SomeAction>();
for (int i = 0; i < list.Count; i++)
{
if (list.ElementAt(i).Action != (SomeAction)i)
{
return false;
}
}
return true;

相关内容

  • 没有找到相关文章