我如何简化条件语句的这一长链?

时间:2018-11-21 01:36:51

标签: c# performance if-statement

我有以下枚举

[Flags]
internal enum DataSectionFlags : uint
{
    TypeReg = 0x0,
    TypeDsect = 0x01,
    TypeNoLoad = 0x02,
    TypeGroup = 0x04,
    TypeNoPadded = 0x08,
    TypeCopy = 0x010,

    ContentCode = 0x020,
    ContentInitializedData = 0x040,
    ContentUninitializedData = 0x080,

    LinkOther = 0x0100,
    LinkInfo = 0x0200,

    TypeOver = 0x0400,

    LinkRemove = 0x0800,
    LinkComDat = 0x01000,

    NoDeferSpecExceptions = 0x04000,

    RelativeGP = 0x08000,

    MemPurgeable = 0x020000,

    Memory16Bit = 0x020000,
    MemoryLocked = 0x040000,
    MemoryPreload = 0x080000,

    Align1Bytes = 0x0100000,
    Align2Bytes = 0x0200000,
    Align4Bytes = 0x0300000,
    Align8Bytes = 0x0400000,
    Align16Bytes = 0x0500000,
    Align32Bytes = 0x0600000,
    Align64Bytes = 0x0700000,
    Align128Bytes = 0x0800000,
    Align256Bytes = 0x0900000,
    Align512Bytes = 0x0A00000,
    Align1024Bytes = 0x0B00000,
    Align2048Bytes = 0x0C00000,
    Align4096Bytes = 0x0D00000,
    Align8192Bytes = 0x0E00000,

    LinkExtendedRelocationOverflow = 0x01000000,

    MemoryDiscardable = 0x02000000,
    MemoryNotCached = 0x04000000,
    MemoryNotPaged = 0x08000000,
    MemoryShared = 0x10000000,
    MemoryExecute = 0x20000000,
    MemoryRead = 0x40000000,
    MemoryWrite = 0x80000000
}

我正在像这样用这个枚举强制转换uint变量

var testVariable = (DataSectionFlags) 1610612768;

我有一个像上面这样处理上述变量的方法

private static uint GetSectionProtection(DataSectionFlags characteristics)
{
    uint result = 0;

    if (characteristics.HasFlag(DataSectionFlags.MemoryNotCached))
    {
        // PageNoCache

        result |= 0x200;
    }

    if (characteristics.HasFlag(DataSectionFlags.MemoryExecute))
    {
        if (characteristics.HasFlag(DataSectionFlags.MemoryRead))
        {
            if (characteristics.HasFlag(DataSectionFlags.MemoryWrite))
            {
                // PageExecuteReadWrite

                result |= 0x40;
            }

            else
            { 
                // PageExecuteRead

                result |= 0x20;
            }

        }

        else if (characteristics.HasFlag(DataSectionFlags.MemoryWrite))
        {
            // PageExecuteWriteCopy

            result |= 0x80;
        }

        else
        {
            // PageExecute

            result |= 0x10;
        }
    }

    else if (characteristics.HasFlag(DataSectionFlags.MemoryRead))
    {
        if (characteristics.HasFlag(DataSectionFlags.MemoryWrite))
        {
            // PageReadWrite

            result |= 0x04;
        }

        else
        {
            // PageReadOnly

            result |= 0x02;
        }               
    }

    else if (characteristics.HasFlag(DataSectionFlags.MemoryWrite))
    {
        // PageWriteCopy

        result |= 0x08;
    }

    else
    {
        // PageNoAccess

        result |= 0x01;
    }

    return result;
}

我正在尝试简化此方法中的长条条件语句,但是这样做很麻烦。

在保持其功能的同时在方法内部编写条件语句的最简单方法是什么?

2 个答案:

答案 0 :(得分:4)

我建议使用类似以下的查找字典:

var sectionProtection = new Dictionary<DataSectionFlags, uint>
{
    [DataSectionFlags.TypeReg ] = 1,
    [DataSectionFlags.TypeDsect ] = 2,
    ...
    [DataSectionFlags.MemoryExecute | DataSectionFlags.MemoryRead | DataSectionFlags.MemoryWrite] = 0x40,
    ...
};

请注意,每种标志组合都需要一个单独的条目。在这种情况下,您可以使用以下语句替换函数

var testVariable = sectionProtection[(DataSectionFlags) 1610612768];

,或者,如果没有定义每个组合,则:

if (sectionProtection.TryGetValue((DataSectionFlags) 1610612768, out testVariable ))

我认为这不仅更易于理解,运行更快,而且更正确。在创建if ... else if ... else if ...语句列表时,很容易错过组合,使相同的组合返回不同的值或两次包含相同的组合。如果您错过了查询字典中的组合,则会得到一个异常(或TryGetValue返回false)。如果将相同的组合两次添加到字典中,则会出现错误。

答案 1 :(得分:1)

这是我能在短时间内提出的最佳建议:

private static uint GetSectionProtection(DataSectionFlags characteristics)
{
    uint result = 0;

    if (characteristics.HasFlag(DataSectionFlags.MemoryNotCached))
    {
        // PageNoCache
        result |= 0x200;
    }

    var ladder = new KeyValuePair<DataSectionFlags[], uint>[]
    {
        new KeyValuePair<DataSectionFlags[], uint>(new [] { DataSectionFlags.MemoryExecute, DataSectionFlags.MemoryRead, DataSectionFlags.MemoryWrite, }, 0x40),
        new KeyValuePair<DataSectionFlags[], uint>(new [] { DataSectionFlags.MemoryExecute, DataSectionFlags.MemoryRead, }, 0x20),
        new KeyValuePair<DataSectionFlags[], uint>(new [] { DataSectionFlags.MemoryExecute, DataSectionFlags.MemoryWrite, }, 0x80),
        new KeyValuePair<DataSectionFlags[], uint>(new [] { DataSectionFlags.MemoryExecute, }, 0x10),
        new KeyValuePair<DataSectionFlags[], uint>(new [] { DataSectionFlags.MemoryRead, DataSectionFlags.MemoryWrite, }, 0x04),
        new KeyValuePair<DataSectionFlags[], uint>(new [] { DataSectionFlags.MemoryRead, }, 0x02),
        new KeyValuePair<DataSectionFlags[], uint>(new [] { DataSectionFlags.MemoryWrite, }, 0x08),
        new KeyValuePair<DataSectionFlags[], uint>(new DataSectionFlags[] { }, 0x01),
    };

    result |= ladder.Where(x => x.Key.All(y => characteristics.HasFlag(y))).First().Value;

    return result;
}

可能更易读的版本:

private static uint GetSectionProtection(DataSectionFlags characteristics)
{
    uint result = 0;

    if (characteristics.HasFlag(DataSectionFlags.MemoryNotCached))
    {
        // PageNoCache
        result |= 0x200;
    }

    var ladder = new []
    {
        new { Flags = new [] { DataSectionFlags.MemoryExecute, DataSectionFlags.MemoryRead, DataSectionFlags.MemoryWrite, }, Value = (uint)0x40 },
        new { Flags = new [] { DataSectionFlags.MemoryExecute, DataSectionFlags.MemoryRead, }, Value = (uint)0x20 },
        new { Flags = new [] { DataSectionFlags.MemoryExecute, DataSectionFlags.MemoryWrite, }, Value = (uint)0x80 },
        new { Flags = new [] { DataSectionFlags.MemoryExecute, }, Value = (uint)0x10 },
        new { Flags = new [] { DataSectionFlags.MemoryRead, DataSectionFlags.MemoryWrite, }, Value = (uint)0x04 },
        new { Flags = new [] { DataSectionFlags.MemoryRead, }, Value = (uint)0x02 },
        new { Flags = new [] { DataSectionFlags.MemoryWrite, }, Value = (uint)0x08 },
        new { Flags = new DataSectionFlags[] { }, Value = (uint)0x01 },
    };

    result |= ladder.Where(x => x.Flags.All(y => characteristics.HasFlag(y))).First().Value;

    return result;
}