繁体   English   中英

比较 c# 中的枚举的最佳和高效方法是什么?

[英]What is the best and performant way to compare enums in c#?

我正在努力比较枚举。 我已经测试了 5 种不同的方式(等于、HasFlag、== 运算符、按位运算符和 is 运算符)。 其中两个(HasFlag 和 Equal)不是用于比较两个枚举的好方法。 但是其他三种方式让我感到困惑。 我试图对它们进行基准测试,但它们给了我各种结果。 这里的测试方法。

[Flags]
public enum Typess
{
    First = 2,
    Second = 4,

public int testCount = 1000;
public int sampleCount = 10000000;

GC.Collect();
var stopwatch = new Stopwatch();
float avarageTime1 = 0f;

for (int i = 0; i < testCount; i++)
{
    stopwatch.Reset();
    stopwatch.Start();
    for (int j = 0; j < sampleCount; j++)
    {
        TestEnum(Typess.First);   
    }
    stopwatch.Stop();
    avarageTime1 += stopwatch.ElapsedMilliseconds;
}
Debug.Log(" Enum Test Consumed time : " + avarageTime1 / (float)testCount + " ms");

GC.Collect();
float avarageTime2 = 0f;
for (int i = 0; i < testCount; i++)
{
    stopwatch.Reset();
    stopwatch.Start();
    for (int j = 0; j < sampleCount; j++)
    {
        TestEnumByte(Typess.First);   
    }
    stopwatch.Stop();
    avarageTime2 += stopwatch.ElapsedMilliseconds;
}
Debug.Log("Enum Byte Test Consumed time : " + avarageTime2 / (float)testCount  + " ms");

GC.Collect();
float avarageTime3 = 0f;
for (int i = 0; i < testCount; i++)
{
    stopwatch.Reset();
    stopwatch.Start();
    for (int j = 0; j < sampleCount; j++)
    {
        TestEnumIs(Typess.First);   
    }
    stopwatch.Stop();
    avarageTime3 += stopwatch.ElapsedMilliseconds;
}
Debug.Log("Enum Is Test Consumed time : " + avarageTime3 / (float)testCount  + " ms");

private bool TestEnum(Typess testType) => testType == Typess.Second;
private bool TestEnumByte(Typess testType) => (testType & Typess.Second) != 0;
private bool TestEnumIs(Typess testType) => testType is Typess.Second;

为什么这三种方法给我不同的结果? 难道我做错了什么? 谢谢

让我们改进您的测试工具:

IEnumerable<TimeSpan> GenerateTestRuns(Func<Typess, bool> f, int samples)
{
    while (true)
    {
        int generation = GC.GetGeneration(0);
        Stopwatch stopwatch = Stopwatch.StartNew();
        for (int j = 0; j < samples; j++)
        {
            f(Typess.First);
        }
        stopwatch.Stop();
        if (generation == GC.GetGeneration(0))
        {
            yield return stopwatch.Elapsed;
        }
    }
}

这段代码的美妙之处在于它会产生零次或多次运行的测试,其中没有垃圾 collections 缺点是如果一直有垃圾collections这段代码会陷入死循环。

在这种情况下,它运行良好并且始终产生价值。

这是我运行的测试:

Dictionary<string, Func<Typess, bool>> fs = new Dictionary<string, Func<Typess, bool>>()
{
    { "testType == Typess.Second", testType => testType == Typess.Second },
    { "(testType & Typess.Second) != 0", testType => (testType & Typess.Second) != 0 },
    { "testType is Typess.Second", testType => testType is Typess.Second },
};

现在实际运行测试的代码是这样的:

int testCount = 1000;
int sampleCount = 10000000;

Dictionary<string, TimeSpan> results = fs.ToDictionary(x => x.Key, x => TimeSpan.Zero);

for (int i = 0; i < testCount; i++)
{
    foreach (KeyValuePair<string, Func<Typess, bool>> kvp in fs)
    {
        foreach (TimeSpan ts in GenerateTestRuns(kvp.Value, sampleCount).Take(1))
        {
            results[kvp.Key] += ts;
        }
    }
}

foreach (KeyValuePair<string, TimeSpan> kvp in results)
{
    Console.WriteLine($"{kvp.Key} each run in {kvp.Value.TotalMilliseconds / testCount} ms");
}

我使用优化代码运行,并检查 IL 是否正在调用函数。

我得到的结果相当一致:

(1)

testType == Typess.Second each run in 21.3049772 ms
(testType & Typess.Second) != 0 each run in 21.321223999999997 ms
testType is Typess.Second each run in 26.525582 ms

(2)

testType == Typess.Second each run in 20.9722699 ms
(testType & Typess.Second) != 0 each run in 20.9309871 ms
testType is Typess.Second each run in 26.0593333 ms

==运算符:此运算符比较两个枚举变量的值,如果相等则返回true ,否则返回false 这是比较两个枚举值的推荐方法,因为它快速且高效。

按位运算符:您可以使用按位运算符&来比较用[Flags]属性修饰的枚举值。 此运算符检查第一个枚举值是否包含第二个枚举值中的所有标志。

is 运算符: is 运算符检查 object 是否属于特定类型。 它可用于检查枚举值是否属于特定枚举类型,但不建议将其用于比较两个枚举值,因为它比其他选项更慢且效率更低。 执行额外的类型检查。

通常, ==运算符是比较枚举值的最有效方法,其次是[Flags]枚举值的按位 & 运算符。 由于性能较低,通常应避免使用 Equal 方法和is运算符来比较枚举值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM