简体   繁体   English

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

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

I am struggling with comparing enums.我正在努力比较枚举。 I have tested 5 different way(Equal, HasFlag, == operator, bitwise operator and is operator).我已经测试了 5 种不同的方式(等于、HasFlag、== 运算符、按位运算符和 is 运算符)。 Two of them(HasFlag and Equal) are not good way to use for comparing two enums.其中两个(HasFlag 和 Equal)不是用于比较两个枚举的好方法。 But other three ways are confusing me.但是其他三种方式让我感到困惑。 I was trying to benchmark them but they are giving to me various results.我试图对它们进行基准测试,但它们给了我各种结果。 Here the test methods.这里的测试方法。

[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;

Why these three methods giving me various result?为什么这三种方法给我不同的结果? Am I doing something wrong?难道我做错了什么? Thanks谢谢

Let's improve your test harness:让我们改进您的测试工具:

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;
        }
    }
}

The beauty of this code is that it will produce zero or more runs of the test where there were no garbage collections .这段代码的美妙之处在于它会产生零次或多次运行的测试,其中没有垃圾 collections The downside is that if there are always garbage collections this code will be stuck in an infinite loop.缺点是如果一直有垃圾collections这段代码会陷入死循环。

It worked fine and always produced values in this case.在这种情况下,它运行良好并且始终产生价值。

Here are the tests I ran:这是我运行的测试:

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 },
};

Now the code to actually run the tests is this:现在实际运行测试的代码是这样的:

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");
}

I ran using optimized code and I checked that the IL was calling the functions.我使用优化代码运行,并检查 IL 是否正在调用函数。

The results I got were fairly consistent:我得到的结果相当一致:

(1) (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) (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

== operator: This operator compares the values of two enum variables and returns true if they are equal, or false if they are not. ==运算符:此运算符比较两个枚举变量的值,如果相等则返回true ,否则返回false This is the recommended way to compare two enum values, as it is fast and efficient.这是比较两个枚举值的推荐方法,因为它快速且高效。

Bitwise operator: You can use the bitwise & operator to compare enum values that are decorated with the [Flags] attribute.按位运算符:您可以使用按位运算符&来比较用[Flags]属性修饰的枚举值。 This operator checks if the first enum value contains all the flags in the second enum value.此运算符检查第一个枚举值是否包含第二个枚举值中的所有标志。

is operator: The is operator checks if an object is of a particular type. is 运算符: is 运算符检查 object 是否属于特定类型。 It can be used to check if an enum value is of a specific enum type, but it is not recommended to use it for comparing two enum values, as it is slower and less efficient than the other options.它可用于检查枚举值是否属于特定枚举类型,但不建议将其用于比较两个枚举值,因为它比其他选项更慢且效率更低。 Additional type checking is performed.执行额外的类型检查。

In general, the == operator is the most efficient way to compare enum values, followed by the bitwise & operator for [Flags] enum values.通常, ==运算符是比较枚举值的最有效方法,其次是[Flags]枚举值的按位 & 运算符。 The Equal method and is operator should generally be avoided for comparing enum values due to their lower performance.由于性能较低,通常应避免使用 Equal 方法和is运算符来比较枚举值。

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

相关问题 是否有一种优雅(或更高效)的方式来(不)迭代 C# 枚举? - Is there an elegant (or more performant) way to (not) iterate through C# enums? 比较两个不同枚举的最佳方法是什么? - What is the best way to compare two different enums? 比较C#中忽略大小写的2个字符的最佳方法是什么? - What is the best way to compare 2 characters ignoring case in C#? 在C#中比较复杂对象的两个列表的最佳方法是什么 - What is the best way to compare two list of complex object in c# 在C#中比较2个整数列表/数组的最佳方法是什么? - What is the best way to compare 2 integer lists / array in C# 在C#中,将字符串与null进行比较以及“”返回true的最佳方法是什么 - In C#, what is the best way to compare strings with null and “” return true 比较 c# 中两个对象的最佳方法是什么 - What is the best way to compare two objects in c# C#比较类字段的最佳方法 - C# Best way to compare fields of class C#:有没有一种方法可以对枚举进行分类? - C#: Is there a way to classify enums? C#比较双精度值和一系列值并返回两个文本值的最佳方法是什么 - C# What is the best way to compare a double value to a range of values and return two text values
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM