我有以下示例:
public class Commands
{
public int ID { get; set; }
public List<string> Alias { get; set; }
}
public class UserAccess
{
public int AccessID { get; set; }
// other stuff not needed for the question
public List<Commands> AllowedCommands { get; set; }
}
现在我想在UserAccess上实现一种返回命令ID的方法,如果列表中没有找到别名,则返回NULL,请参阅下面我说的一个脏例子 {{1} }:
HasCommand
我的问题是运行或实施HasCommand方法的最有效方法是什么?
或者有更好的方法将其实施到UserAccess中吗?
答案 0 :(得分:6)
可以缩短一点
public Commands HasCommand(string cmd)
{
return AllowedCommands.FirstOrDefault(c => c.Alias.Contains(cmd, StringComparer.OrdinalIgnoreCase));
}
但它几乎是一样的。
答案 1 :(得分:2)
public Commands HasCommand(string cmd)
{
return this.AllowedCommands.FirstOrDefault(item => item.Alias.Find(x => string.Equals(x, cmd, StringComparison.OrdinalIgnoreCase)) != null);
}
您不需要使用Where + FirstOrDefault。 FirstOrDefault可以有条件。
答案 2 :(得分:0)
另外,有3项建议需要进一步改进:
(1)如果可能,我会鼓励使用IEnumerable而不是List (2)我将“命令”称为“命令” (3)我会通过这样的类来轻松引用所有命令:
public class Command {
public Command(int id, IEnumerable<string> aliases) {
Id = id;
Aliases = alias;
}
public int Id { get; set; }
public IEnumerable<string> Aliases { get; set; }
}
public class Commands {
public static readonly Command CommandNameHere1(yourIdHere1, yourAliasesHere1);
public static readonly Command CommandNameHere2(yourIdHere2, yourAliasesHere2);
//etc.
}
答案 3 :(得分:0)
假设通过“高效”,您的意思是快速,无论何时您在字符串集合中查找字符串,并且该集合可能包含多个条目,您应该始终使用哈希查找。当项目数量增加时,对列表进行简单扫描需要指数时间,而计数对哈希查找几乎没有影响。在.NET中,传统上这是由Dictionary类处理的,它通常用于使用键(通常是字符串)索引对象集合。但是,该值不能为null,这导致将相同的字符串作为键和值传递 - 相当丑陋。最后,.NET 4提供了HashSet,你应该将它用于只有一个键而没有值的情况。
在您的情况下,您有(并非罕见)需要不区分大小写的比较的情况。对此的常见解决方案是在将字符串键添加到字典(或HashSet)时对其进行小写。由于所有程序员都应该知道并理解不区分大小写的比较速度比区分大小的慢,特别是使用Unicode - CPU不能只对数据进行块比较,因此查找的节省大大超过了添加的这一微小开销。 ,但必须特别检查每对字符(即使使用查表,这也要慢得多)。
如果您的别名可以是小写,请将它们从List更改为HashSet。如果不是,请使用字典,其中键被添加为小写,并且值是(混合大小写)别名字符串。假设使用Dictionary,您的代码将变为:
public Commands HasCommand(string cmd)
{
foreach (Commands item in AllowedCommands)
{
if (item.Alias.ContainsKey(cmd))
return item;
}
return null;
}
最后,关于性能问题,使用LINQ几乎总是会导致性能降低 - 介于两者之间,慢一点,慢一点,具体取决于具体情况。它确实为简单的事情做了很好的,紧凑的源代码,我自己也使用它很多,但是如果你确定性能是一段代码的问题,你可能不应该使用它(除非它是PLINQ,当然)。
因此,如果您想要尽可能少的代码行,请使用此处发布的其他答案。如果你想要速度,请使用我的。
这几乎不言而喻,但是当你担心像这样的一小块代码的性能时,只需将它包装在for循环中并重复它直到执行需要5-10秒 - 只需添加命令根据需要,无论是1,000或1,000,000个代表,还是使用System.Diagnostics.Stopwatch计时。尝试替代逻辑,并重复测试。 5-10秒是最小的,旨在掩盖由托管环境和在同一台机器上执行的其他内容引起的波动(显然,您应该避免在测试期间运行其他应用程序)。当然,对于复杂应用程序的整体性能测试,建议使用性能分析器工具。