C# 这是搜索子字符串最有效的方法吗?

C# 这是搜索子字符串最有效的方法吗?,c#,performance,C#,Performance,我正在使用一些代码,这些代码返回一个代码来指示用户的类型(例如“a”、“B”、“C”、“D”等)。每个代码对应一个特定的角色和/或范围(例如,在整个应用程序中或仅针对正在处理的对象) 在我正在查看的一些代码中,我看到了一些调用,这些调用用于检查用户的代码是否是多个代码中的一个,以便允许他们执行某些操作。所以我看到这样的电话: //"B" would come from the database string userCode = "B"; //some more work... //if t

我正在使用一些代码,这些代码返回一个代码来指示用户的类型(例如“a”、“B”、“C”、“D”等)。每个代码对应一个特定的角色和/或范围(例如,在整个应用程序中或仅针对正在处理的对象)

在我正在查看的一些代码中,我看到了一些调用,这些调用用于检查用户的代码是否是多个代码中的一个,以便允许他们执行某些操作。所以我看到这样的电话:

//"B" would come from the database
string userCode = "B";

//some more work...

//if the user's code is either A or C...
if("AC".IndexOf(userCode) >= 0) {
  //do work that allows the user to progress
} else {
  //notify user they can't do this operation
}
这是执行此检查的有效方法吗?有没有更有效的方法

提前谢谢

使用Contains()函数是一种选择。我不知道它相对于索引的性能如何,但它是一个选项:

string userCode = "B";
string someStringToSearchIn = "Current user is: B";

if (someStringToSearchIn.Contains(userCode))
{
    //do something
}

如果要查找单个字符,并且它不区分大小写,请使用与字符一起工作的重载。搜索单个不区分大小写的字符比搜索子字符串快

"AC".IndexOf('C');
不过,这对于这件事来说是至关重要的。用任何明显的方法,你所做的都会非常快

更新-计时

[Test]
public void Time()
{
    const string UserCode = "C";
    const char UserCodeChar = 'C';
    const int Iterations = 10000000;

    double adjust = 0;

    Func<Action, double> time = action =>
    {
        Stopwatch sw = Stopwatch.StartNew();
        for (int i = 0; i < Iterations; i++) action();
        return sw.Elapsed.TotalMilliseconds;
    };

    Action<string, Action> test = (desc, t) =>
    {
        double ms = time(t) - adjust;
        Console.WriteLine(desc + " time: {0}ms", ms);
    };

    adjust = time(() => { });

    test("IndexOfString", () => "AC".IndexOf(UserCode));
    test("IndexOfString", () => "AC".IndexOf(UserCode));

    test("ContainsString", () => "AC".Contains(UserCode));
    test("ContainsString", () => "AC".Contains(UserCode));

    test("IndexOfChar", () => "AC".IndexOf(UserCodeChar));
    test("IndexOfChar", () => "AC".IndexOf(UserCodeChar));
}
[测试]
公共空闲时间()
{
常量字符串UserCode=“C”;
const char UserCodeChar='C';
const int迭代次数=10000000;
双重调整=0;
Func time=操作=>
{
秒表sw=Stopwatch.StartNew();
对于(int i=0;i
{
双ms=时间(t)-调整;
Console.WriteLine(desc+“时间:{0}ms”,ms);
};
调整=时间(()=>{});
测试(“IndexOfString”,()=>AC.IndexOf(UserCode));
测试(“IndexOfString”,()=>AC.IndexOf(UserCode));
测试(“ContainsString”,()=>“AC”.Contains(UserCode));
测试(“ContainsString”,()=>“AC”.Contains(UserCode));
测试(“IndexOfChar”,()=>AC.IndexOf(UserCodeChar));
测试(“IndexOfChar”,()=>AC.IndexOf(UserCodeChar));
}
结果:

索引字符串时间:1035.2984ms
索引字符串时间:1026.2889毫秒
包含字符串时间:764.9274ms
包含字符串时间:736.7621ms
IndexOfChar时间:92.9008ms
IndexOfChar时间:92.9961ms


查看
Contains()
的反编译代码,它只调用
IndexOf()
StringComparison.Ordinal
,因此我认为
IndexOf()
如果以相同的方式(Ordinal)使用,效率最高(非常小),因为它只有一个方法调用,但是
Contains()
更具可读性,因此更易于维护

public bool Contains(string value)
{
    return (this.IndexOf(value, StringComparison.Ordinal) >= 0);
}
正如所有事情一样,我会选择可读性和可维护性更好的,然后再对性能进行微调。只有当您知道此时存在瓶颈时才进行微观优化

更新:超过1000000次迭代:

  • 包含(值)-耗时130毫秒
  • IndexOf(value,StringComparison.Ordinal)-耗时128毫秒
正如你所看到的,非常非常接近。再一次,使用更易于维护的方法

更新2:如果您的代码始终是单字符(而不是单字符字符串),IndexOf()会更快:

  • 包含(字符值)-耗时94毫秒
  • IndexOf(字符值)-耗时16毫秒
如果您知道您的字符代码始终是单个字符,那么使用带有字符参数的
IndexOf()
大约快一个数量级

这是因为
Contains(char-value)
IEnumerable
的扩展方法,而不是
string
的第一类方法


但是再一次,100万次迭代中的100毫秒实际上是可以忽略不计的。

我认为您可以假设系统库的实现非常有效,并且您通常无法使用自制的解决方案来加快速度。也就是说,我认为您编码用户类型的方式非常奇怪。为什么不使用位掩码或类似的东西呢?除此之外,我认为你的问题根本不重要:与访问数据库和做“一些工作”相比,你的检查根本不重要。

至少在我的电脑上,
包含
字符串的
(而不是
字符的
)是最快的

结果:
时间索引:616ms
包含时间:499ms
包含字符时间:707ms

代码:

static void Main(字符串[]args)
{
字符串userCode=“B”;
char userCodeChar='B';
整数迭代次数=10000000;
var sw=Stopwatch.StartNew();
对于(int i=0;i=0)
{
INTA=1+1;
}
}
sw.Stop();
WriteLine(“IndexOf time:{0}ms”,sw.elapsedmillesons);
sw=秒表。开始新();
对于(int i=0;i
首先,我不太清楚您为什么关心这里的效率。您正在执行非常短的字符串搜索,这不太可能影响性能

尽管如此,我还是觉得这种风格令人困惑。如果您想知道
userCode
是否是“A”和“C”中的一个,只需这样说:

if (userCode.Equals("A") || userCode.Equals("C"))
{
    // Do something useful
}
晶莹剔透,最有可能的性能以及

作为补充说明,如果您可以将这些代码放入
enum
,事情可能会简单得多:

[Flags]
public enum UserCode
{
    None = 0,
    A = 1,
    B = 2,
    C = 4
}
现在你可以说:

if ((userCode & (UserCode.A | UserCode.C)) != UserCode.None)
{
    // Do something even more useful
}
这是落后的
if ((userCode & (UserCode.A | UserCode.C)) != UserCode.None)
{
    // Do something even more useful
}