我正在处理一些代码,这些代码返回一个代码来指示它们的用户类型(例如“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
}
这是执行此检查的有效方式吗?有更有效的方法吗?
提前致谢!
答案 0 :(得分:5)
查看Contains()
的解压缩代码,只需使用IndexOf()
调用StringComparison.Ordinal
,因此我认为IndexOf()
效率最高(非常小)我是否以相同的方式使用(Ordinal),因为它只有少一个方法调用,但Contains()
更具可读性,因此更易于维护......
public bool Contains(string value)
{
return (this.IndexOf(value, StringComparison.Ordinal) >= 0);
}
就像在所有事情中一样,我会选择更具可读性和可维护性的东西,然后分解性能。当你知道此时存在瓶颈时,才进行微优化。
更新:超过1,000,000次迭代:
所以你可以看到,非常非常接近。再一次,用更可维护的东西。
UPDATE 2 :如果您的代码始终是单个字符(不是1-char字符串),则IndexOf()更快:
如果您知道您的char代码始终是一个char,那么将IndexOf()
与char参数一起使用会快一个数量级。
这是因为Contains(char value)
是IEnumerable<T>
之外的扩展方法,而不是string
的第一类方法。
但再次在100,000次迭代中再次~100 ms真的,真的,可以忽略不计。
答案 1 :(得分:3)
如果您正在寻找单个字符,并且它不区分大小写,请使用与char一起使用的重载。搜索单个不区分大小写的char比子字符串更快。
"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));
}
结果:
IndexOfString时间:1035.2984ms
IndexOfString时间:1026.2889ms
包含字符串时间:764.9274ms
包含字符串时间:736.7621ms
IndexOfChar时间:92.9008ms
IndexOfChar时间:92.9961ms
答案 2 :(得分:3)
我认为您可以假设系统库的实现非常高效,并且您通常无法使用自制解决方案加快速度。也就是说,我认为你对用户类型进行编码的方式很奇怪。为什么不使用Bitmasks或类似的东西?除此之外,我认为你的问题根本不相关:比较D来访问数据库并做“一些工作”你的支票根本不重要。
答案 3 :(得分:1)
使用Contains()函数是一个选项。我不知道它与索引的表现如何,但它是一个选项:
string userCode = "B";
string someStringToSearchIn = "Current user is: B";
if (someStringToSearchIn.Contains(userCode))
{
//do something
}
答案 4 :(得分:0)
首先,我不确定你为何关注这里的效率。您正在执行极短字符串搜索,这不太可能降低性能。
话虽如此,我实际上发现这种风格令人困惑。如果你想知道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
}
答案 5 :(得分:-1)
至少在我的计算机上,Contains
string
(而不是char
)是最快的。
结果:
IndexOf时间:616ms
包含时间:499ms
包含字符时间:707ms
代码:
static void Main(string[] args)
{
string userCode = "B";
char userCodeChar = 'B';
int iterations = 10000000;
var sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
if ("AC".IndexOf(userCode) >= 0)
{
int a = 1 + 1;
}
}
sw.Stop();
Console.WriteLine("IndexOf time: {0}ms", sw.ElapsedMilliseconds);
sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
if ("AC".Contains(userCode))
{
int a = 1 + 1;
}
}
sw.Stop();
Console.WriteLine("Contains time: {0}ms", sw.ElapsedMilliseconds);
sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
if ("AC".Contains(userCodeChar))
{
int a = 1 + 1;
}
}
sw.Stop();
Console.WriteLine("Contains char time: {0}ms", sw.ElapsedMilliseconds);
Console.WriteLine("Done");
Console.ReadLine();
}