1

我有以下示例:

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 的方法,如果在列表中没有找到别名,请看下面我所说的一个肮脏的例子 HasCommand

public class UserAccess
{
    public ID { get; set; }
    // other stuff not needed for the question
    public List<Commands> AllowedCommands { get; set; }

    public Commands HasCommand(string cmd)
    {
        foreach (Commands item in this.AllowedCommands)
        {
            if (item.Alias.Find(x => string.Equals(x, cmd, StringComparison.OrdinalIgnoreCase)) != null)
                return item;
        }
        return null;
    }
}
  • 我的问题是运行或实现 HasCommand 方法的最有效方法是什么?

  • 还是有更好的方法将其实施到 UserAccess 中?

4

4 回答 4

6

可以缩短一点

public Commands HasCommand(string cmd)
{
    return AllowedCommands.FirstOrDefault(c => c.Alias.Contains(cmd, StringComparer.OrdinalIgnoreCase));

}

但这几乎是一回事。

于 2011-10-04T17:35:27.113 回答
2
public Commands HasCommand(string cmd)
    {
        return this.AllowedCommands.FirstOrDefault(item => item.Alias.Find(x => string.Equals(x, cmd, StringComparison.OrdinalIgnoreCase)) != null);
    }

您不需要使用 Where + FirstOrDefault。FirstOfDefault 可以有条件。

于 2011-10-04T17:55:18.260 回答
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.
}
于 2011-10-04T17:52:46.563 回答
0

假设“高效”是指快速,只要您在字符串集合中查找字符串,并且该集合可能包含多个条目,您应该始终使用哈希查找。随着项目计数的增加,对列表进行简单扫描需要指数级的时间,而计数对哈希查找几乎没有影响。在 .NET 中,这通常由 Dictionary 类处理,该类通常用于索引具有键(通常是字符串)的对象集合。但是,该值不能为空,这导致将相同的字符串作为键和值传递 - 相当难看。最后,.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 秒是最低限度,旨在掩盖由托管环境和在同一台机器上执行的其他内容引起的波动(您显然还应该避免在测试期间运行其他应用程序)。当然,对于复杂应用程序的整体性能测试,建议使用性能分析器工具。

于 2011-10-04T18:13:21.543 回答