我们可以在C#中定义枚举的隐式转换吗?


129

是否可以在C#中定义枚举的隐式转换?

什么可以实现这一目标?

public enum MyEnum
{
    one = 1, two = 2
}

MyEnum number = MyEnum.one;
long i = number;

如果没有,为什么不呢?


2
我也想这样做。我们有一个enum YesNo {Yes, No}可以隐式转换为bool 的枚举。
Panic Panic 2014年

注意,此概念会禁用编译器类型安全检查。从长远来看,像尾随“〜”这样的显式转换速记可能会更好。
crokusek

该链接不再有效-我们可以删除该链接,还是将网站重新发布到某个地方?
ワイきんぐ

Answers:


128

有一个解决方案。考虑以下:

public sealed class AccountStatus
{
    public static readonly AccountStatus Open = new AccountStatus(1);
    public static readonly AccountStatus Closed = new AccountStatus(2);

    public static readonly SortedList<byte, AccountStatus> Values = new SortedList<byte, AccountStatus>();
    private readonly byte Value;

    private AccountStatus(byte value)
    {
        this.Value = value;
        Values.Add(value, this);
    }


    public static implicit operator AccountStatus(byte value)
    {
        return Values[value];
    }

    public static implicit operator byte(AccountStatus value)
    {
        return value.Value;
    }
}

上面提供了隐式转换:

        AccountStatus openedAccount = 1;            // Works
        byte openedValue = AccountStatus.Open;      // Works

这比声明一个普通的枚举要花更多的功夫(尽管您可以将上述内容重构为一个通用的通用基类)。通过使基类实现IComparable和IEquatable,以及添加方法以返回DescriptionAttributes的值,声明的名称等,您可以走得更远。

我编写了一个基类(RichEnum <>)来处理大多数艰苦的工作,这使上面的枚举声明简化为:

public sealed class AccountStatus : RichEnum<byte, AccountStatus>
{
    public static readonly AccountStatus Open = new AccountStatus(1);
    public static readonly AccountStatus Closed = new AccountStatus(2);

    private AccountStatus(byte value) : base (value)
    {
    }

    public static implicit operator AccountStatus(byte value)
    {
        return Convert(value);
    }
}

下面列出了基类(RichEnum)。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Resources;

namespace Ethica
{
    using Reflection;
    using Text;

    [DebuggerDisplay("{Value} ({Name})")]
    public abstract class RichEnum<TValue, TDerived>
                : IEquatable<TDerived>,
                  IComparable<TDerived>,
                  IComparable, IComparer<TDerived>
        where TValue : struct , IComparable<TValue>, IEquatable<TValue>
        where TDerived : RichEnum<TValue, TDerived>
    {
        #region Backing Fields

        /// <summary>
        /// The value of the enum item
        /// </summary>
        public readonly TValue Value;

        /// <summary>
        /// The public field name, determined from reflection
        /// </summary>
        private string _name;

        /// <summary>
        /// The DescriptionAttribute, if any, linked to the declaring field
        /// </summary>
        private DescriptionAttribute _descriptionAttribute;

        /// <summary>
        /// Reverse lookup to convert values back to local instances
        /// </summary>
        private static SortedList<TValue, TDerived> _values;

        private static bool _isInitialized;


        #endregion

        #region Constructors

        protected RichEnum(TValue value)
        {
            if (_values == null)
                _values = new SortedList<TValue, TDerived>();
            this.Value = value;
            _values.Add(value, (TDerived)this);
        }

        #endregion

        #region Properties

        public string Name
        {
            get
            {
                CheckInitialized();
                return _name;
            }
        }

        public string Description
        {
            get
            {
                CheckInitialized();

                if (_descriptionAttribute != null)
                    return _descriptionAttribute.Description;

                return _name;
            }
        }

        #endregion

        #region Initialization

        private static void CheckInitialized()
        {
            if (!_isInitialized)
            {
                ResourceManager _resources = new ResourceManager(typeof(TDerived).Name, typeof(TDerived).Assembly);

                var fields = typeof(TDerived)
                                .GetFields(BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public)
                                .Where(t => t.FieldType == typeof(TDerived));

                foreach (var field in fields)
                {

                    TDerived instance = (TDerived)field.GetValue(null);
                    instance._name = field.Name;
                    instance._descriptionAttribute = field.GetAttribute<DescriptionAttribute>();

                    var displayName = field.Name.ToPhrase();
                }
                _isInitialized = true;
            }
        }

        #endregion

        #region Conversion and Equality

        public static TDerived Convert(TValue value)
        {
            return _values[value];
        }

        public static bool TryConvert(TValue value, out TDerived result)
        {
            return _values.TryGetValue(value, out result);
        }

        public static implicit operator TValue(RichEnum<TValue, TDerived> value)
        {
            return value.Value;
        }

        public static implicit operator RichEnum<TValue, TDerived>(TValue value)
        {
            return _values[value];
        }

        public static implicit operator TDerived(RichEnum<TValue, TDerived> value)
        {
            return value;
        }

        public override string ToString()
        {
            return _name;
        }

        #endregion

        #region IEquatable<TDerived> Members

        public override bool Equals(object obj)
        {
            if (obj != null)
            {
                if (obj is TValue)
                    return Value.Equals((TValue)obj);

                if (obj is TDerived)
                    return Value.Equals(((TDerived)obj).Value);
            }
            return false;
        }

        bool IEquatable<TDerived>.Equals(TDerived other)
        {
            return Value.Equals(other.Value);
        }


        public override int GetHashCode()
        {
            return Value.GetHashCode();
        }

        #endregion

        #region IComparable Members

        int IComparable<TDerived>.CompareTo(TDerived other)
        {
            return Value.CompareTo(other.Value);
        }

        int IComparable.CompareTo(object obj)
        {
            if (obj != null)
            {
                if (obj is TValue)
                    return Value.CompareTo((TValue)obj);

                if (obj is TDerived)
                    return Value.CompareTo(((TDerived)obj).Value);
            }
            return -1;
        }

        int IComparer<TDerived>.Compare(TDerived x, TDerived y)
        {
            return (x == null) ? -1 :
                   (y == null) ? 1 :
                    x.Value.CompareTo(y.Value);
        }

        #endregion

        public static IEnumerable<TDerived> Values
        {
            get
            {
                return _values.Values;
            }
        }

        public static TDerived Parse(string name)
        {
            foreach (TDerived value in _values.Values)
                if (0 == string.Compare(value.Name, name, true) || 0 == string.Compare(value.DisplayName, name, true))
                    return value;

            return null;
        }
    }
}

更正了帖子中的一些后卫错误:-)这是公共静态隐式运算符AccountStatus(byte value){return Convert(value); }不返回Convert(byte);
Mehdi LAMRANI 2011年

我对此基类进行了编译。您介意我编辑更改吗?
sehe 2011年

64
作为练习或测试某人的编程技能,此解决方案可能是“正确的”,但是请不要在现实生活中这样做。它不仅杀伤力大,而且效率低下,难以维护且丑陋。您不必仅仅为了枚举而使用枚举。您可以进行显式转换,也可以只编写带有const ints的静态类。
陷阱

3
它基本上不是重新实现的Java枚举吗?
Agent_L

2
一个主要问题是您不能在switch语句中使用这些静态只读常量。
伊恩·高德比

34

您不能进行隐式转换(零除外),也不能编写自己的实例方法-但是,您可能可以编写自己的扩展方法:

public enum MyEnum { A, B, C }
public static class MyEnumExt
{
    public static int Value(this MyEnum foo) { return (int)foo; }
    static void Main()
    {
        MyEnum val = MyEnum.A;
        int i = val.Value();
    }
}

但是,这并不能给您带来太多好处(与仅进行显式转换相比)。

我见过人们希望这样做的主要时间之一是[Flags]通过泛型(即bool IsFlagSet<T>(T value, T flag);方法)进行操作。不幸的是,C#3.0不支持泛型运算符,但是您可以使用this这样的方法来解决此问题,这使运算符可完全使用泛型。


是的,那是我最想要的C#4之一:stackoverflow.com/questions/138367/…stackoverflow.com/questions/7244
Keith,

@Keith-做得不错,然后;-p动态/操作员支持并未纳入CTP,但是我准备好了一个测试平台,以比较动态(+)操作员的两种方法。对比泛型/表达式)。
马克·格雷韦尔

@Keith-您可能想给MiscUtil中的Operator类一个旋转;我很确定它将满足您的大部分需求。
马克·格雷韦尔

22
struct PseudoEnum
{
    public const int 
              INPT = 0,
              CTXT = 1,
              OUTP = 2;
};

// ...

var arr = new String[3];

arr[PseudoEnum.CTXT] = "can";
arr[PseudoEnum.INPT] = "use";
arr[PseudoEnum.CTXT] = "as";
arr[PseudoEnum.CTXT] = "array";
arr[PseudoEnum.OUTP] = "index";

但是为什么要构造呢?
康拉德

1
真的没有理由。你可以用static class我想的。在最终IL代码中争论两种情况都没有优势。
Glenn Slayden

18

我改编了Mark出色的RichEnum通用基类。

定影

  1. 由于缺少库中的位而导致的许多编译问题(特别是:与资源相关的显示名称尚未完全删除;现在已删除)
  2. 初始化不是完美的:如果您所做的第一件事是从基类访问static .Values属性,那么您将获得一个NPE。通过强制基类好奇地递归CRTP)强制在CheckInitialized期间及时构造TDerived的静态结构来解决此问题
  3. 最终将CheckInitialized逻辑移到了静态构造函数中(为避免每次检查多线程初始化时的竞争条件带来的麻烦;也许这是不可能的,我的项目符号1.解决了这一问题?)

马克(Mark)出色的想法+实施的荣誉,给大家:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Resources;

namespace NMatrix
{

    [DebuggerDisplay("{Value} ({Name})")]
    public abstract class RichEnum<TValue, TDerived>
                : IEquatable<TDerived>,
                  IComparable<TDerived>,
                  IComparable, IComparer<TDerived>
        where TValue : struct, IComparable<TValue>, IEquatable<TValue>
        where TDerived : RichEnum<TValue, TDerived>
    {
        #region Backing Fields

        /// <summary>
        /// The value of the enum item
        /// </summary>
        public readonly TValue Value;

        /// <summary>
        /// The public field name, determined from reflection
        /// </summary>
        private string _name;

        /// <summary>
        /// The DescriptionAttribute, if any, linked to the declaring field
        /// </summary>
        private DescriptionAttribute _descriptionAttribute;

        /// <summary>
        /// Reverse lookup to convert values back to local instances
        /// </summary>
        private static readonly SortedList<TValue, TDerived> _values = new SortedList<TValue, TDerived>();

        #endregion

        #region Constructors

        protected RichEnum(TValue value)
        {
            this.Value = value;
            _values.Add(value, (TDerived)this);
        }

        #endregion

        #region Properties

        public string Name
        {
            get
            {
                return _name;
            }
        }

        public string Description
        {
            get
            {
                if (_descriptionAttribute != null)
                    return _descriptionAttribute.Description;

                return _name;
            }
        }

        #endregion

        #region Initialization

        static RichEnum()
        {
            var fields = typeof(TDerived)
                .GetFields(BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public)
                .Where(t => t.FieldType == typeof(TDerived));

            foreach (var field in fields)
            {
                /*var dummy =*/ field.GetValue(null); // forces static initializer to run for TDerived

                TDerived instance = (TDerived)field.GetValue(null);
                instance._name = field.Name;
                                    instance._descriptionAttribute = field.GetCustomAttributes(true).OfType<DescriptionAttribute>().FirstOrDefault();
            }
        }

        #endregion

        #region Conversion and Equality

        public static TDerived Convert(TValue value)
        {
            return _values[value];
        }

        public static bool TryConvert(TValue value, out TDerived result)
        {
            return _values.TryGetValue(value, out result);
        }

        public static implicit operator TValue(RichEnum<TValue, TDerived> value)
        {
            return value.Value;
        }

        public static implicit operator RichEnum<TValue, TDerived>(TValue value)
        {
            return _values[value];
        }

        public static implicit operator TDerived(RichEnum<TValue, TDerived> value)
        {
            return value;
        }

        public override string ToString()
        {
            return _name;
        }

        #endregion

        #region IEquatable<TDerived> Members

        public override bool Equals(object obj)
        {
            if (obj != null)
            {
                if (obj is TValue)
                    return Value.Equals((TValue)obj);

                if (obj is TDerived)
                    return Value.Equals(((TDerived)obj).Value);
            }
            return false;
        }

        bool IEquatable<TDerived>.Equals(TDerived other)
        {
            return Value.Equals(other.Value);
        }


        public override int GetHashCode()
        {
            return Value.GetHashCode();
        }

        #endregion

        #region IComparable Members

        int IComparable<TDerived>.CompareTo(TDerived other)
        {
            return Value.CompareTo(other.Value);
        }

        int IComparable.CompareTo(object obj)
        {
            if (obj != null)
            {
                if (obj is TValue)
                    return Value.CompareTo((TValue)obj);

                if (obj is TDerived)
                    return Value.CompareTo(((TDerived)obj).Value);
            }
            return -1;
        }

        int IComparer<TDerived>.Compare(TDerived x, TDerived y)
        {
            return (x == null) ? -1 :
                   (y == null) ? 1 :
                    x.Value.CompareTo(y.Value);
        }

        #endregion

        public static IEnumerable<TDerived> Values
        {
            get
            {
                return _values.Values;
            }
        }

        public static TDerived Parse(string name)
        {
            foreach (TDerived value in Values)
                if (0 == string.Compare(value.Name, name, true))
                    return value;

            return null;
        }
    }
}

我在mono上运行的用法示例:

using System.ComponentModel;
using System;

namespace NMatrix
{    
    public sealed class MyEnum : RichEnum<int, MyEnum>
    {
        [Description("aap")]  public static readonly MyEnum my_aap   = new MyEnum(63000);
        [Description("noot")] public static readonly MyEnum my_noot  = new MyEnum(63001);
        [Description("mies")] public static readonly MyEnum my_mies  = new MyEnum(63002);

        private MyEnum(int value) : base (value) { } 
        public static implicit operator MyEnum(int value) { return Convert(value); }
    }

    public static class Program
    {
        public static void Main(string[] args)
        {
            foreach (var enumvalue in MyEnum.Values)
                Console.WriteLine("MyEnum {0}: {1} ({2})", (int) enumvalue, enumvalue, enumvalue.Description);
        }
    }
}

产生输出

[mono] ~/custom/demo @ gmcs test.cs richenum.cs && ./test.exe 
MyEnum 63000: my_aap (aap)
MyEnum 63001: my_noot (noot)
MyEnum 63002: my_mies (mies)

注意:单声道2.6.7需要额外的显式强制转换,而使用单声道2.8.2则不需要...


使用.Single()获取description属性不是一个好主意。如果没有属性,则Single()会引发异常,而SingleOrDefault()不会。
kerem 2012年

@kerem好点,我对其进行了更新(使用FirstOrDefault,以避免假设只有一个属性)。当然,假设这样的事情是否是一个“好主意”(或坏的想法),取决于上下文
sehe 2012年

1
喜欢这个,但是我遇到了一个问题:在Windows 7 / .NET 4.5上,此行的TDerived instance = (TDerived)field.GetValue(null);结果instancenull。看来,Mono运行时必须具有与.NET相同的类型初始化顺序,以使它可以工作。令人费解!相反,我不得不将该代码移到静态方法中,并从子类的类型初始值设定项中调用它。
agentnega 2014年

@agentnega感谢您的补充。它可能会帮助某人。
sehe 2014年

@agentnega我在.net 4.5.1上遇到了同样的问题。似乎“违反”了C#规范 b / c,它在首次使用之前没有初始化值-至少在使用反射时没有初始化。我实现了一种变通方法,不需要涉及子类(“ TDerived”)。@ sehe我应该编辑您的答案并将解决方法添加到您的答案中,还是应该发布新答案?
BatteryBackupUnit 2015年


4

您可能可以,但不能使用枚举(您不能向其中添加方法)。您可以将隐式转换添加到自己的类中,以允许将枚举转换为该类,

public class MyClass {

    public static implicit operator MyClass ( MyEnum input ) {
        //...
    }
}

MyClass m = MyEnum.One;

问题是为什么?

通常,.Net避免了(并且您也应该避免)任何可能丢失数据的隐式转换。


3

如果将枚举的基数定义为long,则可以执行显式转换。我不知道您是否可以使用隐式转换,因为枚举不能在其上定义方法。

public enum MyEnum : long
{
    one = 1,
    two = 2,
}

MyEnum number = MyEnum.one;
long i = (long)number;

另外,请注意,未初始化的枚举将默认为0值或第一项-因此在上述情况下,最好也进行定义zero = 0


5
您不需要: long这里;没有它,显式转换就可以正常工作。唯一合法的隐式转换为零。
马克·格雷韦尔

3
没有; 默认枚举是Int32
Marc Gravell

1
请参见:枚举Foo {A,B,C} Console.WriteLine(Enum.GetUnderlyingType(typeof(Foo)));
马克·格雷韦尔

14
为什么将此标记为答案并有很多要点?这与OP问题无关!他正在谈论IMPLICIT Conversion ...附加值是nil。
Mehdi LAMRANI 2011年

3
这个问题已经暗示要理解显式强制转换,这个问题等效于询问“我如何避免显式强制转换?”,该帖子不适用于该示例。
套件10

2

枚举对我来说基本上没有用。

我最终总是做与图片相关的事情:

简单的解决方案

经典示例问题是用于检测按键的VirtualKey集。

enum VKeys : ushort
{
a = 1,
b = 2,
c = 3
}
// the goal is to index the array using predefined constants
int[] array = new int[500];
var x = array[VKeys.VK_LSHIFT]; 

这里的问题是您不能用枚举索引数组,因为它不能将枚举隐式转换为ushort(即使我们甚至将枚举基于ushort)

在此特定上下文中,以下数据结构淘汰了枚举。。。。

public static class VKeys
{
public const ushort
a = 1,
b = 2, 
c = 3;
}

1

我已经解决了sehe答案的问题在MS .net(非Mono)上运行代码时,。对我来说,这个问题专门出现在.net 4.5.1上,但其他版本似乎也受到了影响。

问题

访问public static TDervied MyEnumValue由反射(通过FieldInfo.GetValue(null)确实初始化所述场。

解决方法

无需TDerived在静态初始值设定项上为实例分配名称,而是RichEnum<TValue, TDerived>在第一次访问时懒惰地完成TDerived.Name。代码:

public abstract class RichEnum<TValue, TDerived> : EquatableBase<TDerived>
    where TValue : struct, IComparable<TValue>, IEquatable<TValue>
    where TDerived : RichEnum<TValue, TDerived>
{
    // Enforcing that the field Name (´SomeEnum.SomeEnumValue´) is the same as its 
    // instances ´SomeEnum.Name´ is done by the static initializer of this class.
    // Explanation of initialization sequence:
    // 1. the static initializer of ´RichEnum<TValue, TDerived>´ reflects TDervied and 
    //    creates a list of all ´public static TDervied´ fields:
    //   ´EnumInstanceToNameMapping´
    // 2. the static initializer of ´TDerive´d assigns values to these fields
    // 3. The user is now able to access the values of a field.
    //    Upon first access of ´TDervied.Name´ we search the list 
    //    ´EnumInstanceToNameMapping´ (created at step 1) for the field that holds
    //    ´this´ instance of ´TDerived´.
    //    We then get the Name for ´this´ from the FieldInfo
    private static readonly IReadOnlyCollection<EnumInstanceReflectionInfo> 
                            EnumInstanceToNameMapping = 
        typeof(TDerived)
            .GetFields(BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public)
            .Where(t => t.FieldType == typeof(TDerived))
            .Select(fieldInfo => new EnumInstanceReflectionInfo(fieldInfo))
            .ToList();

    private static readonly SortedList<TValue, TDerived> Values =
        new SortedList<TValue, TDerived>();

    public readonly TValue Value;

    private readonly Lazy<string> _name;

    protected RichEnum(TValue value)
    {
        Value = value;

        // SortedList doesn't allow duplicates so we don't need to do
        // duplicate checking ourselves
        Values.Add(value, (TDerived)this);

        _name = new Lazy<string>(
                    () => EnumInstanceToNameMapping
                         .First(x => ReferenceEquals(this, x.Instance))
                         .Name);
    }

    public string Name
    {
        get { return _name.Value; }
    }

    public static implicit operator TValue(RichEnum<TValue, TDerived> richEnum)
    {
        return richEnum.Value;
    }

    public static TDerived Convert(TValue value)
    {
        return Values[value];
    }

    protected override bool Equals(TDerived other)
    {
        return Value.Equals(other.Value);
    }

    protected override int ComputeHashCode()
    {
        return Value.GetHashCode();
    }

    private class EnumInstanceReflectionInfo
    {
        private readonly FieldInfo _field;
        private readonly Lazy<TDerived> _instance;

        public EnumInstanceReflectionInfo(FieldInfo field)
        {
            _field = field;
            _instance = new Lazy<TDerived>(() => (TDerived)field.GetValue(null));
        }

        public TDerived Instance
        {
            get { return _instance.Value; }
        }

        public string Name { get { return _field.Name; } }
    }
}

就我而言,这是基于EquatableBase<T>

public abstract class EquatableBase<T>
    where T : class 
{
    public override bool Equals(object obj)
    {
        if (this == obj)
        {
            return true;
        }

        T other = obj as T;
        if (other == null)
        {
            return false;
        }

        return Equals(other);
    }

    protected abstract bool Equals(T other);

    public override int GetHashCode()
    {
        unchecked
        {
            return ComputeHashCode();
        }
    }

    protected abstract int ComputeHashCode();
}

注意

上面的代码未包含Mark的所有功能原始答案的!

谢谢

感谢Mark提供的RichEnum实现,也感谢sehe提供了一些改进!


1

我发现从这里采取的更简单的解决方案/codereview/7566/enum-vs-int-wrapper-struct我从该链接粘贴了以下代码,以防万一将来无法使用。

struct Day
{
    readonly int day;

    public static readonly Day Monday = 0;
    public static readonly Day Tuesday = 1;
    public static readonly Day Wednesday = 2;
    public static readonly Day Thursday = 3;
    public static readonly Day Friday = 4;
    public static readonly Day Saturday = 5;
    public static readonly Day Sunday = 6;

    private Day(int day)
    {
        this.day = day;
    }

    public static implicit operator int(Day value)
    {
        return value.day;
    }

    public static implicit operator Day(int value)
    {
        return new Day(value);
    }
}

1

我创建了此实用程序,以帮助我将Enum转换为PrimitiveEnum并将PrimitiveEnum转换为byte, sbyte, short, ushort, int, uint, long, or ulong

因此,从技术上讲,这会将任何枚举转换为其原始值。

public enum MyEnum
{
    one = 1, two = 2
}

PrimitiveEnum number = MyEnum.one;
long i = number;

请参阅https://github.com/McKabue/McKabue.Extentions.Utility/blob/master/src/McKabue.Extentions.Utility/Enums/PrimitiveEnum.cs上的提交

using System;

namespace McKabue.Extentions.Utility.Enums
{
    /// <summary>
    /// <see href="https://stackoverflow.com/q/261663/3563013">
    /// Can we define implicit conversions of enums in c#?
    /// </see>
    /// </summary>
    public struct PrimitiveEnum
    {
        private Enum _enum;

        public PrimitiveEnum(Enum _enum)
        {
            this._enum = _enum;
        }

        public Enum Enum => _enum;


        public static implicit operator PrimitiveEnum(Enum _enum)
        {
            return new PrimitiveEnum(_enum);
        }

        public static implicit operator Enum(PrimitiveEnum primitiveEnum)
        {
            return primitiveEnum.Enum;
        }

        public static implicit operator byte(PrimitiveEnum primitiveEnum)
        {
            return Convert.ToByte(primitiveEnum.Enum);
        }

        public static implicit operator sbyte(PrimitiveEnum primitiveEnum)
        {
            return Convert.ToSByte(primitiveEnum.Enum);
        }

        public static implicit operator short(PrimitiveEnum primitiveEnum)
        {
            return Convert.ToInt16(primitiveEnum.Enum);
        }

        public static implicit operator ushort(PrimitiveEnum primitiveEnum)
        {
            return Convert.ToUInt16(primitiveEnum.Enum);
        }

        public static implicit operator int(PrimitiveEnum primitiveEnum)
        {
            return Convert.ToInt32(primitiveEnum.Enum);
        }

        public static implicit operator uint(PrimitiveEnum primitiveEnum)
        {
            return Convert.ToUInt32(primitiveEnum.Enum);
        }

        public static implicit operator long(PrimitiveEnum primitiveEnum)
        {
            return Convert.ToInt64(primitiveEnum.Enum);
        }

        public static implicit operator ulong(PrimitiveEnum primitiveEnum)
        {
            return Convert.ToUInt64(primitiveEnum.Enum);
        }
    }
}

+1我有一个游戏框架,其中有许多由uints 标识的东西,而游戏本身通常enum为此做s,但该框架一无所知。在(uint)调用框架时必须付出一定的努力。您的想法倒向完美。而不是struct存储Enum,我有一个struct IdNumber,其中存储了,uint但从Enum游戏使用的隐式转换了。uint我可以键入它们IdNumber,而不用将框架的参数键入为,并且框架可以在内部有效地传递它们,甚至可以对它们进行整体操作。
凯文

-2

为枚举类型引入隐式转换会破坏类型安全性,因此不建议这样做。你为什么想这么做?我所看到的唯一用例是,当您要将枚举值放入具有预定义布局的结构中时。但是即使这样,您也可以在结构中使用枚举类型,并告诉Marshaller应该如何处理。


我有一个隐式转换枚举的用途。使用SPMetal在同一网站集的多个网站中生成LINQ to SharePoint类。我的一些列表在一个子站点中,其他列表在另一子站点中。由于SPMetal是如何生成代码的,因此可以在多个名称空间中定义在集合的多个列表中使用的站点列。但是,我需要在一个命名空间中的选择字段枚举与另一个命名空间中的相同枚举之间进行转换。隐式转换将非常有帮助。
扎里菲斯(Zarepheth)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.