在 C# 中,如何轻松地将枚举标志从一种类型映射到另一种类型?

发布于 2024-08-20 03:12:57 字数 2746 浏览 2 评论 0原文

另请参阅问题末尾的更新...

考虑到以下情况:

[Flags]
enum SourceEnum
{
    SNone = 0x00,

    SA = 0x01,
    SB = 0x02,
    SC = 0x04,
    SD = 0x08,

    SAB = SA | SB,

    SALL = -1,
}

[Flags]
enum DestEnum
{
    DNone = 0x00,

    DA = 0x01,
    DB = 0x02,
    DC = 0x04,

    DALL = 0xFF,
}

我想根据使用大名称等名称的映射函数将一种枚举类型转换为另一种枚举类型,反之亦然switch() 但由于这是一个标志枚举,我很难设计这样一个通用的例程。

基本上,我想要的是如下所示:

示例#1

SourceEnum source = SourceEnum.SA;
DestEnum dest = Map<Source, Dest> (source);
Assert.That (dest, Is.EqualTo (DestEnum.DA));

示例#2

SourceEnum source = SourceEnum.SA | SourceEnum.SB;
DestEnum dest = Map<Source, Dest> (source);
Assert.That (dest, Is.EqualTo (DestEnum.DA | DestEnum.DB));

示例#3

SourceEnum source = SourceEnum.SAB;
DestEnum dest = Map<Source, Dest> (source);
Assert.That (dest, Is.EqualTo (DestEnum.DA | DestEnum.DB));

示例#4

SourceEnum source = SourceEnum.SALL;
DestEnum dest = Map<Source, Dest> (source);
Assert.That (dest, Is.EqualTo (DestEnum.DALL));

示例#5

SourceEnum source = SourceEnum.SD;
var ex = Assert.Throws<Exception> (() => Map<Source, Dest> (source));
Assert.That (ex.Message, Is.EqualTo ("Cannot map SourceEnum.SD to DestEnum!"));

Map() 函数可以接受委托来提供实际映射,但我仍然需要几个函数来提供帮助这样一个带有位的委托...

DestEnum SourceToDestMapper (SourceEnum source)
{
    // Switch cannot work with bit fields enumeration...
    // This is to give the general idea...
    switch (source)
    {
        case SourceEnum.SNone:
            return DestEnum.DNone;

        case SourceEnum.SA:
            return DestEnum.DA;

        case SourceEnum.SAB:
            return DestEnum.DA | DestEnum.DB;

        ...

        default:
            throw new Exception ("Cannot map " + source.ToString() + " to DestEnum!");
    }
}

编辑:澄清

枚举定义的值可能看起来彼此适合,但情况不一定如此。

例如,它可能是:

enum SourceEnum
{
    SA = 0x08,
    SB = 0x20,
    SC = 0x10,
    SAB = SA | SB,
    SABC = SA | SB | SC,
}

enum DestEnum
{
    DA = 0x04,
    DB = 0x80,
    DC = 0x01,
    DAB = DA | DB,
}

编辑:更多信息

我正在寻找一种进行枚举标志的自定义映射的方法,而不是基于名称上的模式。但是,这些名称用于自定义映射函数。

例如,我完全有可能有一个 SourceToDestMapper 函数尝试将 SA 映射到 DC...

主要问题是为 SourceToDestMapper 函数提供源的每个标志,并处理具有多个位集的标志值...

例如: 具有标志 SourceEnum.SABC 将调用 SourceToDestMapper 函数 3 次,结果如下:

  • SourceEnum.SA 映射到 DestEnum.DA
  • SourceEnum.SB 映射到 DestEnum.DB
  • SourceEnum.SC 映射到 DestEnum.DC

生成的 DestEnum 将是: DestEnum .DA | DestEnum.DB |目标枚举.DC

Also see the updates at the end of the question...

Given the following situation:

[Flags]
enum SourceEnum
{
    SNone = 0x00,

    SA = 0x01,
    SB = 0x02,
    SC = 0x04,
    SD = 0x08,

    SAB = SA | SB,

    SALL = -1,
}

[Flags]
enum DestEnum
{
    DNone = 0x00,

    DA = 0x01,
    DB = 0x02,
    DC = 0x04,

    DALL = 0xFF,
}

I would like to convert one enum type to the other and vice-versa based on mapping function using the names like a big switch() but since this a flags enum I am having a difficult time designing such a routine to be generic.

Basically, what I want is something like the following:

Example #1

SourceEnum source = SourceEnum.SA;
DestEnum dest = Map<Source, Dest> (source);
Assert.That (dest, Is.EqualTo (DestEnum.DA));

Example #2

SourceEnum source = SourceEnum.SA | SourceEnum.SB;
DestEnum dest = Map<Source, Dest> (source);
Assert.That (dest, Is.EqualTo (DestEnum.DA | DestEnum.DB));

Example #3

SourceEnum source = SourceEnum.SAB;
DestEnum dest = Map<Source, Dest> (source);
Assert.That (dest, Is.EqualTo (DestEnum.DA | DestEnum.DB));

Example #4

SourceEnum source = SourceEnum.SALL;
DestEnum dest = Map<Source, Dest> (source);
Assert.That (dest, Is.EqualTo (DestEnum.DALL));

Example #5

SourceEnum source = SourceEnum.SD;
var ex = Assert.Throws<Exception> (() => Map<Source, Dest> (source));
Assert.That (ex.Message, Is.EqualTo ("Cannot map SourceEnum.SD to DestEnum!"));

The Map() function could accept a delegate for providing the actual mapping but I still need to have several functions for helping such a delegate with the bits...

DestEnum SourceToDestMapper (SourceEnum source)
{
    // Switch cannot work with bit fields enumeration...
    // This is to give the general idea...
    switch (source)
    {
        case SourceEnum.SNone:
            return DestEnum.DNone;

        case SourceEnum.SA:
            return DestEnum.DA;

        case SourceEnum.SAB:
            return DestEnum.DA | DestEnum.DB;

        ...

        default:
            throw new Exception ("Cannot map " + source.ToString() + " to DestEnum!");
    }
}

EDIT: CLARIFICATION

The values of the enum definitions might seem to fit between each others but that is not necessarily the case.

For example, it could be:

enum SourceEnum
{
    SA = 0x08,
    SB = 0x20,
    SC = 0x10,
    SAB = SA | SB,
    SABC = SA | SB | SC,
}

enum DestEnum
{
    DA = 0x04,
    DB = 0x80,
    DC = 0x01,
    DAB = DA | DB,
}

EDIT: More info

I am looking at a way of doing a custom mapping of enum flags, not based on patterns on the names. However, the names are used in the custom mapping function.

I would be perfectly possible to have a SourceToDestMapper function trying to map SA to DC for example...

The main problem is feeding the SourceToDestMapper function with each flag of the source AND taking care of flag values having multiple bit sets...

For example:
Having a flag SourceEnum.SABC would call the SourceToDestMapper function three times resulting in the following:

  • SourceEnum.SA mapped to DestEnum.DA
  • SourceEnum.SB mapped to DestEnum.DB
  • SourceEnum.SC mapped to DestEnum.DC

And the resulting DestEnum would be: DestEnum.DA | DestEnum.DB | DestEnum.DC

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

弥繁 2024-08-27 03:12:57

您还可以使用扩展方法将 SourceEnum 转换为 DestEnum,这里是代码带有一些单元测试

或使用另一个很棒的工具,例如 ValueInjecter :http://valueinjecter.codeplex.com/

 [Flags]
public enum SourceEnum
{
    SA = 0x08,
    SB = 0x20,
    SC = 0x10,
    SAB = SA | SB,
    SABC = SA | SB | SC
}
[Flags]
public enum DestEnum
{
    DA = 0x04,
    DB = 0x80,
    DC = 0x01,
    DAB = DA | DB
}
public static class ExtensionTests
{

    public static SourceEnum ToSourceEnum(this DestEnum destEnum)
    {
        SourceEnum toSourceEnum=0x0;
        if ((destEnum & DestEnum.DA) == DestEnum.DA)
            toSourceEnum |= SourceEnum.SA;
        if ((destEnum & DestEnum.DB) == DestEnum.DB)
            toSourceEnum |= SourceEnum.SB;
        if ((destEnum & DestEnum.DC) == DestEnum.DC)
            toSourceEnum |= SourceEnum.SC;

        return toSourceEnum;
    }
    public static DestEnum ToDestEnum(this SourceEnum sourceEnum)
    {
        DestEnum toDestEnum=0;
        if ((sourceEnum & SourceEnum.SA) == SourceEnum.SA)
            toDestEnum = toDestEnum | DestEnum.DA;
        if ((sourceEnum & SourceEnum.SB) == SourceEnum.SB)
            toDestEnum = toDestEnum | DestEnum.DB;
        if ((sourceEnum & SourceEnum.SC) == SourceEnum.SC)
            toDestEnum = toDestEnum | DestEnum.DC;

        return toDestEnum;
    }
}


/// <summary>
///This is a test class for ExtensionMethodsTest and is intended
///to contain all ExtensionMethodsTest Unit Tests
///</summary>
[TestClass()]
public class ExtensionMethodsTest
{
    #region Sources
    [TestMethod]
    public void ExtensionMethodsTest_SourceEnum_SA_inverts()
    {
        //then you code goes like this...
        SourceEnum sourceEnum = SourceEnum.SA;
        Assert.AreEqual(SourceEnum.SA, sourceEnum.ToDestEnum().ToSourceEnum(), "");
        //and vice-versa...
    }

    [TestMethod]
    public void ExtensionMethodsTest_SourceEnum_SAB_inverts()
    {
        //then you code goes like this...
        SourceEnum sourceEnum = SourceEnum.SAB;
        Assert.AreEqual(SourceEnum.SAB, sourceEnum.ToDestEnum().ToSourceEnum());
        //and vice-versa...
    }
    [TestMethod]
    public void ExtensionMethodsTest_SourceEnum_SABC_inverts()
    {
        //then you code goes like this...
        SourceEnum sourceEnum = SourceEnum.SABC;
        Assert.AreEqual(SourceEnum.SABC, sourceEnum.ToDestEnum().ToSourceEnum());
        //and vice-versa...
    }
    [TestMethod]
    public void ExtensionMethodsTest_SourceEnum_SA_Union_SC_inverts()
    {
        //then you code goes like this...
        SourceEnum sourceEnum = SourceEnum.SA | SourceEnum.SC;
        Assert.AreEqual(SourceEnum.SA | SourceEnum.SC, sourceEnum.ToDestEnum().ToSourceEnum());
        //and vice-versa...
    }
    #endregion

    #region Source To Destination
    [TestMethod]
    public void ExtensionMethodsTest_SourceEnum_SA_returns_DestEnum_DA()
    {
        Assert.IsTrue(DestEnum.DA == SourceEnum.SA.ToDestEnum());
    }
    [TestMethod]
    public void ExtensionMethodsTest_SourceEnum_SAB_returns_DestEnum_DAB()
    {
        Assert.IsTrue(DestEnum.DAB == SourceEnum.SAB.ToDestEnum());
    }
    [TestMethod]
    public void ExtensionMethodsTest_SourceEnum_SA_SC_returns_DestEnum_DA_DC()
    {
        Assert.IsTrue((DestEnum.DA | DestEnum.DC) == (SourceEnum.SA | SourceEnum.SC ).ToDestEnum());
    }

    #endregion

    #region Destination to Source
     [TestMethod]
    public void ExtensionMethodsTest_DestEnum_SA_returns_SourceEnum_DA()
    {
        Assert.IsTrue(SourceEnum.SA == DestEnum.DA.ToSourceEnum());
    }
     [TestMethod]
    public void ExtensionMethodsTest_DestEnum_SAB_returns_SourceEnum_DAB()
    {
        Assert.IsTrue(SourceEnum.SAB == DestEnum.DAB.ToSourceEnum());
    }
     [TestMethod]
    public void ExtensionMethodsTest_DestEnum_SABC_returns_SourceEnum_DAB_DC()
    {
        Assert.IsTrue(SourceEnum.SABC == (DestEnum.DAB | DestEnum.DC ).ToSourceEnum());
    }

    #endregion
}

you can also use Extension Methods to transform you SourceEnum to DestEnum, here's the code with some unit tests

or use another great tool such as ValueInjecter : http://valueinjecter.codeplex.com/

 [Flags]
public enum SourceEnum
{
    SA = 0x08,
    SB = 0x20,
    SC = 0x10,
    SAB = SA | SB,
    SABC = SA | SB | SC
}
[Flags]
public enum DestEnum
{
    DA = 0x04,
    DB = 0x80,
    DC = 0x01,
    DAB = DA | DB
}
public static class ExtensionTests
{

    public static SourceEnum ToSourceEnum(this DestEnum destEnum)
    {
        SourceEnum toSourceEnum=0x0;
        if ((destEnum & DestEnum.DA) == DestEnum.DA)
            toSourceEnum |= SourceEnum.SA;
        if ((destEnum & DestEnum.DB) == DestEnum.DB)
            toSourceEnum |= SourceEnum.SB;
        if ((destEnum & DestEnum.DC) == DestEnum.DC)
            toSourceEnum |= SourceEnum.SC;

        return toSourceEnum;
    }
    public static DestEnum ToDestEnum(this SourceEnum sourceEnum)
    {
        DestEnum toDestEnum=0;
        if ((sourceEnum & SourceEnum.SA) == SourceEnum.SA)
            toDestEnum = toDestEnum | DestEnum.DA;
        if ((sourceEnum & SourceEnum.SB) == SourceEnum.SB)
            toDestEnum = toDestEnum | DestEnum.DB;
        if ((sourceEnum & SourceEnum.SC) == SourceEnum.SC)
            toDestEnum = toDestEnum | DestEnum.DC;

        return toDestEnum;
    }
}


/// <summary>
///This is a test class for ExtensionMethodsTest and is intended
///to contain all ExtensionMethodsTest Unit Tests
///</summary>
[TestClass()]
public class ExtensionMethodsTest
{
    #region Sources
    [TestMethod]
    public void ExtensionMethodsTest_SourceEnum_SA_inverts()
    {
        //then you code goes like this...
        SourceEnum sourceEnum = SourceEnum.SA;
        Assert.AreEqual(SourceEnum.SA, sourceEnum.ToDestEnum().ToSourceEnum(), "");
        //and vice-versa...
    }

    [TestMethod]
    public void ExtensionMethodsTest_SourceEnum_SAB_inverts()
    {
        //then you code goes like this...
        SourceEnum sourceEnum = SourceEnum.SAB;
        Assert.AreEqual(SourceEnum.SAB, sourceEnum.ToDestEnum().ToSourceEnum());
        //and vice-versa...
    }
    [TestMethod]
    public void ExtensionMethodsTest_SourceEnum_SABC_inverts()
    {
        //then you code goes like this...
        SourceEnum sourceEnum = SourceEnum.SABC;
        Assert.AreEqual(SourceEnum.SABC, sourceEnum.ToDestEnum().ToSourceEnum());
        //and vice-versa...
    }
    [TestMethod]
    public void ExtensionMethodsTest_SourceEnum_SA_Union_SC_inverts()
    {
        //then you code goes like this...
        SourceEnum sourceEnum = SourceEnum.SA | SourceEnum.SC;
        Assert.AreEqual(SourceEnum.SA | SourceEnum.SC, sourceEnum.ToDestEnum().ToSourceEnum());
        //and vice-versa...
    }
    #endregion

    #region Source To Destination
    [TestMethod]
    public void ExtensionMethodsTest_SourceEnum_SA_returns_DestEnum_DA()
    {
        Assert.IsTrue(DestEnum.DA == SourceEnum.SA.ToDestEnum());
    }
    [TestMethod]
    public void ExtensionMethodsTest_SourceEnum_SAB_returns_DestEnum_DAB()
    {
        Assert.IsTrue(DestEnum.DAB == SourceEnum.SAB.ToDestEnum());
    }
    [TestMethod]
    public void ExtensionMethodsTest_SourceEnum_SA_SC_returns_DestEnum_DA_DC()
    {
        Assert.IsTrue((DestEnum.DA | DestEnum.DC) == (SourceEnum.SA | SourceEnum.SC ).ToDestEnum());
    }

    #endregion

    #region Destination to Source
     [TestMethod]
    public void ExtensionMethodsTest_DestEnum_SA_returns_SourceEnum_DA()
    {
        Assert.IsTrue(SourceEnum.SA == DestEnum.DA.ToSourceEnum());
    }
     [TestMethod]
    public void ExtensionMethodsTest_DestEnum_SAB_returns_SourceEnum_DAB()
    {
        Assert.IsTrue(SourceEnum.SAB == DestEnum.DAB.ToSourceEnum());
    }
     [TestMethod]
    public void ExtensionMethodsTest_DestEnum_SABC_returns_SourceEnum_DAB_DC()
    {
        Assert.IsTrue(SourceEnum.SABC == (DestEnum.DAB | DestEnum.DC ).ToSourceEnum());
    }

    #endregion
}
臻嫒无言 2024-08-27 03:12:57

这是一个简单的解决方案,它只需要一个映射字典并通过扫描它来执行映射。不幸的是 System.Enum 不能用作通用约束,因此我使用处理转换的特定派生类构建了解决方案。

请注意,FlagMapper 的构造函数采用一对相互映射的单个标志。它还可以将多个位映射到多个位,只要您确保映射全部一致即可。如果该对的第一个元素中的所有位在源枚举中均打开,则该对的第二个元素中的位将在目标枚举中设置。

SALL 到 DALL 的映射当前不起作用,因为在我的构造函数中我尚未映射高阶位。我没有做这个映射,因为它有点不符合SD映射失败的要求。

using System;
using System.Collections.Generic;

namespace Flags
{
    [Flags]
    enum SourceEnum
    {
        SNone = 0x00,

        SA = 0x01,
        SB = 0x02,
        SC = 0x04,
        SD = 0x08,

        SAB = SA | SB,

        SALL = -1,
    }

    [Flags]
    enum DestEnum
    {
        DNone = 0x00,

        DA = 0x01,
        DB = 0x02,
        DC = 0x04,

        DALL = 0xFF,
    }

    class FlagMapper
    {
        protected Dictionary<int, int> mForwardMapping;

        protected FlagMapper(Dictionary<int, int> mappings)
        {
            this.mForwardMapping = mappings;
        }

        protected int Map(int a)
        {
            int result = 0;

            foreach (KeyValuePair<int, int> mapping in this.mForwardMapping)
            {
                if ((a & mapping.Key) == mapping.Key)
                {
                    if (mapping.Value < 0)
                    {
                        throw new Exception("Cannot map");
                    }

                    result |= mapping.Value;
                }
            }

            return result;
        }
    }

    class SourceDestMapper : FlagMapper
    {
        public SourceDestMapper()
            : base(new Dictionary<int, int>
            {
                { (int)SourceEnum.SA, (int)DestEnum.DA },
                { (int)SourceEnum.SB, (int)DestEnum.DB },
                { (int)SourceEnum.SC, (int)DestEnum.DC },
                { (int)SourceEnum.SD, -1 }
            })
        {
        }

        public DestEnum Map(SourceEnum source)
        {
            return (DestEnum)this.Map((int)source);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            SourceDestMapper mapper = new SourceDestMapper();

            Console.WriteLine(mapper.Map(SourceEnum.SA));
            Console.WriteLine(mapper.Map(SourceEnum.SA | SourceEnum.SB));
            Console.WriteLine(mapper.Map(SourceEnum.SAB));

            //Console.WriteLine(mapper.Map(SourceEnum.SALL));

            Console.WriteLine(mapper.Map(SourceEnum.SD));
        }
    }
}

Here is a solution that simply takes a dictionary of mappings and performs a mapping by scanning over it. Unfortunately System.Enum can't be used as a generic constraint so I've built up the solution using a specific derived class that handles the casting.

Note that the constructor for FlagMapper takes pairs of single flags that map to each other. It can also map multiple bits to multiple bits so long as you ensure the mappings are all consistent. If all of the bits in the first element of the pair are on in the source enum, then the bits in the second element of the pair will be set in the destination enum.

The mapping for SALL to DALL currently wont work because in my constructor I haven't mapped the higher order bits. I didn't make this mapping because it's kind of inconsistent with the requirement that the mapping of SD fail.

using System;
using System.Collections.Generic;

namespace Flags
{
    [Flags]
    enum SourceEnum
    {
        SNone = 0x00,

        SA = 0x01,
        SB = 0x02,
        SC = 0x04,
        SD = 0x08,

        SAB = SA | SB,

        SALL = -1,
    }

    [Flags]
    enum DestEnum
    {
        DNone = 0x00,

        DA = 0x01,
        DB = 0x02,
        DC = 0x04,

        DALL = 0xFF,
    }

    class FlagMapper
    {
        protected Dictionary<int, int> mForwardMapping;

        protected FlagMapper(Dictionary<int, int> mappings)
        {
            this.mForwardMapping = mappings;
        }

        protected int Map(int a)
        {
            int result = 0;

            foreach (KeyValuePair<int, int> mapping in this.mForwardMapping)
            {
                if ((a & mapping.Key) == mapping.Key)
                {
                    if (mapping.Value < 0)
                    {
                        throw new Exception("Cannot map");
                    }

                    result |= mapping.Value;
                }
            }

            return result;
        }
    }

    class SourceDestMapper : FlagMapper
    {
        public SourceDestMapper()
            : base(new Dictionary<int, int>
            {
                { (int)SourceEnum.SA, (int)DestEnum.DA },
                { (int)SourceEnum.SB, (int)DestEnum.DB },
                { (int)SourceEnum.SC, (int)DestEnum.DC },
                { (int)SourceEnum.SD, -1 }
            })
        {
        }

        public DestEnum Map(SourceEnum source)
        {
            return (DestEnum)this.Map((int)source);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            SourceDestMapper mapper = new SourceDestMapper();

            Console.WriteLine(mapper.Map(SourceEnum.SA));
            Console.WriteLine(mapper.Map(SourceEnum.SA | SourceEnum.SB));
            Console.WriteLine(mapper.Map(SourceEnum.SAB));

            //Console.WriteLine(mapper.Map(SourceEnum.SALL));

            Console.WriteLine(mapper.Map(SourceEnum.SD));
        }
    }
}
以歌曲疗慰 2024-08-27 03:12:57

如果枚举的值在逻辑上是等价的,则可以将一个枚举转换为另一个枚举,例如,

public DestEnum Map(SourceEnum source) {
    return (DestEnum)SourceEnum;
}

如果是这种情况,则可以仅使用几个带有 const int 成员的静态类。

但是,如果 SourceEnum.SA 在逻辑上等同于 DestEnum.DC,或者 SourceEnum.SAB == DestEnum.SomethingElse >,那么你别无选择,只能编写自定义映射。

If the values of your enums are logically equivalent, you can just cast one enum to the other, eg

public DestEnum Map(SourceEnum source) {
    return (DestEnum)SourceEnum;
}

If this is the case, you could just use a couple of static classes with const int members.

However, if SourceEnum.SA is logicially equivalent to DestEnum.DC, or SourceEnum.SAB == DestEnum.SomethingElse, then you've not choice but to write a custom mapping.

饮惑 2024-08-27 03:12:57

我认为沿着这些思路的东西会起作用,假设枚举的名称遵循类似的模式:

public D Map<D, S>(S enumValue, D defaultValue)
    {

        D se = defaultValue; 
        string n = Enum.GetName(typeof(S), enumValue);

        string[] s = Enum.GetNames(typeof(S));
        string[] d = Enum.GetNames(typeof(D));
        foreach (var v in d)
        {
            if (n.Substring(1, n.Length - 1) == v.Substring(1, v.Length - 1))
            {
                se = (D)Enum.Parse(typeof(D), v);
                break;
            }
        }
        return se;
    }

选项 2 是建立一个整数字典来进行映射。

DestEnum de = DestEnum.DNone;
        SourceEnum se = SourceEnum.SA;
        Dictionary<int, int> maps = new Dictionary<int, int>();
        maps.Add((int)SourceEnum.SNone, (int)DestEnum.DNone);
        maps.Add((int)SourceEnum.SAB, (int)(DestEnum.DA | DestEnum.DB));
        maps.Add((int)SourceEnum.SA, (int)DestEnum.DA);
        de = (DestEnum)maps[(int)se];

I think something along these lines would work, assuming that the names of the enums follow a similar pattern:

public D Map<D, S>(S enumValue, D defaultValue)
    {

        D se = defaultValue; 
        string n = Enum.GetName(typeof(S), enumValue);

        string[] s = Enum.GetNames(typeof(S));
        string[] d = Enum.GetNames(typeof(D));
        foreach (var v in d)
        {
            if (n.Substring(1, n.Length - 1) == v.Substring(1, v.Length - 1))
            {
                se = (D)Enum.Parse(typeof(D), v);
                break;
            }
        }
        return se;
    }

Options 2 would be to set up a dictionary of ints to do the mapping..

DestEnum de = DestEnum.DNone;
        SourceEnum se = SourceEnum.SA;
        Dictionary<int, int> maps = new Dictionary<int, int>();
        maps.Add((int)SourceEnum.SNone, (int)DestEnum.DNone);
        maps.Add((int)SourceEnum.SAB, (int)(DestEnum.DA | DestEnum.DB));
        maps.Add((int)SourceEnum.SA, (int)DestEnum.DA);
        de = (DestEnum)maps[(int)se];
浅语花开 2024-08-27 03:12:57

不知道为什么你需要这样做,因为看起来你真的只需要一个枚举。

如果可以安全地假设“等效”枚举值的数值始终相同,那么真正的问题是“提供的值是否设置了不属于目标枚举的任何‘标志’”。实现此目的的一种方法是循环遍历目标枚举的所有可能值。如果设置了 flas,则将其与值进行异或。如果循环结束时值!= 0,则无法转换。

如果可以转换,则只需将值转换为 int,然后转换为新类型。

附言。我是否提到过这样做一开始就很奇怪?

Not sure why you need to do this, since it seems like you really just need one enumeration.

If it is safe to assume that the numeric values of the "equivalent" enum values are always the same, then the real question is "does the supplied value have any 'flags' set which are not part of the target enumeration". One way to do this would be to loop through all possible values for the target enumeration. If the flas is set, then xor it from the value. If the value != 0 at the end of the loop, then it cannot be converted.

If it can be converted, then just cast the value to an int and then to the new type.

PS. Have I mentioned that it is strange to do this in the first place?

疯了 2024-08-27 03:12:57
  public ReturnEnum ConvertEnum<InEnum, ReturnEnum>(InEnum fromEnum)
  {
     ReturnEnum ret = (ReturnEnum)Enum.ToObject(typeof(ReturnEnum), fromEnum);
     if (Enum.IsDefined(typeof(ReturnEnum), ret))
     {
        return ret;
     }
     else
     {
        throw new Exception("Nope"); // TODO: Create more informative error here
     }
  }
  public ReturnEnum ConvertEnum<InEnum, ReturnEnum>(InEnum fromEnum)
  {
     ReturnEnum ret = (ReturnEnum)Enum.ToObject(typeof(ReturnEnum), fromEnum);
     if (Enum.IsDefined(typeof(ReturnEnum), ret))
     {
        return ret;
     }
     else
     {
        throw new Exception("Nope"); // TODO: Create more informative error here
     }
  }
白首有我共你 2024-08-27 03:12:57

泛型字典被实现为哈希表,因此算法的复杂度是 O(1)。因此,如果枚举相当大,这是最快的方法。

编辑:
为了澄清...假设您有多个声明转换规则的委托,其中一个是默认的(SA->DA),让我们命名为:default_delegate。

class MyMapper
{
    delegate DestEnum singlemap(SourceEnum);
    static Dictionary<SourceEnum, singlemap> _source2dest = 
       new Dictionary<SourceEnum, singlemap>();
    static MyMapper()
    {
         //place there non-default conversion
         _source2dest[S_xxxx] = My_delegate_to_cast_S_xxxx;
         ......
    }
    static singlemap MapDelegate(SourceEnum se)
    {
        singlemap retval;
        //checking has complexity O(1)
        if(_source2dest.TryGetValue ( se, out retval) )
            return retval;
        return default_delegate;
    }

因此,当调用 MyMapper.MapDelegate 时,随时返回 deleage 来执行映射。

generic Dictionary is implemented as hashtable, hence complexity of algorithm is O(1). So if enum rather large it is most fast way.

EDITED:
To clarify... Assume you have multiple delegates that declares rule of conversion, where ONE of them is default (SA->DA), let's name: default_delegate.

class MyMapper
{
    delegate DestEnum singlemap(SourceEnum);
    static Dictionary<SourceEnum, singlemap> _source2dest = 
       new Dictionary<SourceEnum, singlemap>();
    static MyMapper()
    {
         //place there non-default conversion
         _source2dest[S_xxxx] = My_delegate_to_cast_S_xxxx;
         ......
    }
    static singlemap MapDelegate(SourceEnum se)
    {
        singlemap retval;
        //checking has complexity O(1)
        if(_source2dest.TryGetValue ( se, out retval) )
            return retval;
        return default_delegate;
    }

So when calling MyMapper.MapDelegate returns anytime deleage for performing mapping.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文