问题描述
可以在c#中定义枚举的隐式转换?
public enum MyEnum
{
one = 1,two = 2
}
MyEnum number = MyEnum.one;
long i = number;
如果没有,为什么不这样?
有关这方面的进一步讨论和想法,我跟踪了我目前如何处理这个问题:
有一个解决方案。请考虑以下内容:
公开封闭的类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>();
私有readonly字节值;
private AccountStatus(byte value)
{
this.Value = value;
Values.Add(value,this);
}
public static implicit operator AccountStatus(byte value)
{
返回值[byte];
}
public static implicit operator byte(AccountStatus value)
{
return value.Value;
}
}
以上提供隐式转换:
AccountStatus openedAccount = 1; // Works
byte openedValue = AccountStatus.Open; // Works
这比宣称一般的枚举更有用处(虽然可以重构一些以上为通用基类)。你可以通过让基类实现IComparable& IEquatable,以及添加方法来返回DescriptionAttributes的值,声明的名称等等。
我写了一个基类(RichEnum)来处理大多数fo咕噜的工作,简化了以上声明的枚举:
公开密码类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)如下所示。 / p>
using System;
使用System.Collections.Generic;
使用System.ComponentModel;
使用System.Diagnostics;
使用System.Linq;
使用System.Reflection;
使用System.Resources;
命名空间Ethica
{
using Reflection;
使用文字;
[DebuggerDisplay({Value}({Name}))]
public abstract class RichEnum< TValue,TDerived>
:IEquatable< TDerived>
IComparable< TDerived>
IComparable,IComparer< TDerived>
其中TValue:struct,IComparable< TValue>,IEquatable< TValue>
其中TDerived:RichEnum< TValue,TDerived>
{
#region Backing Fields
///< summary>
///枚举项的值
///< / summary>
public readonly TValue Value;
///< summary>
///公共字段名称,由反射确定
///< / summary>
私有字符串_name;
///< summary>
///将DescriptionAttribute(如果有)链接到声明字段
///< / summary>
private DescriptionAttribute _descriptionAttribute;
///< summary>
///反向查找将值转换回本地实例
///< / summary>
private static SortedList< TValue,TDerived> _values;
private static bool _isInitialized;
#endregion
#region构造函数
protected RichEnum(TValue value)
{
if( _values == null)
_values = new SortedList< TValue,TDerived>();
this.Value = value;
_values.Add(value,(TDerived)this);
}
#endregion
#region属性
public string Name
{
get
{
CheckInitialized();
return _name;
}
}
public string描述
{
get
{
CheckInitialized();
if(_descriptionAttribute!= null)
return _descriptionAttribute.Description;
return _name;
}
}
#endregion
#region初始化
private static void CheckInitialized()
{
如果(!_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字段)
{
TDerived instance =(TDerived)field.GetValue(null);
instance._name = field.Name;
instance._descriptionAttribute = field.GetAttribute< DescriptionAttribute>();
var displayName = field.Name.ToPhrase();
}
_isInitialized = true;
}
}
#endregion
#region转换和平等
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)
{
返回值;
}
public override string ToString()
{
return _name;
}
#endregion
#region IEquatable< TDerived>成员
public override bool Equals(object obj)
{
if(obj!= null)
{
if(obj为TValue)
return Value.Equals((TValue)obj);
if(obj为TDerived)
返回Value.Equals(((TDerived)obj).Value);
}
返回false;
}
bool IEquatable< TDerived> .Equals(TDerived other)
{
return Value.Equals(other.Value);
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
#endregion
#region IComparable会员
int IComparable< TDerived> .CompareTo(TDerived other)
{
return Value.CompareTo(other.Value);
int IComparable.CompareTo(object obj)
{
if(obj!= null)
{
if(obj是TValue)
return Value.CompareTo((TValue)obj);
if(obj为TDerived)
返回值.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>值
{
get
{
return _values.Values;
}
}
public static TDerived Parse(string name)
{
foreach(_values.Values中的TDerived值)
if( 0 == string.Compare(value.Name,name,true)|| 0 == string.Compare(value.DisplayName,name,true))
返回值;
返回null;
}
}
}
Is it possible to define an implicit conversion of enums in c#?
something that could achieve this?
public enum MyEnum
{
one = 1, two = 2
}
MyEnum number = MyEnum.one;
long i = number;
If not, why not?
For further discussion and ideas on this, I followed up with how I currently handle this: Improving the C# enum
There is a solution. Consider the following:
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[byte];
}
public static implicit operator byte(AccountStatus value)
{
return value.Value;
}
}
The above offers implicit conversion:
AccountStatus openedAccount = 1; // Works
byte openedValue = AccountStatus.Open; // Works
This is a fair bit more work than declaring a normal enum (though you can refactor some of the above into a common generic base class). You can go even further by having the base class implement IComparable & IEquatable, as well as adding methods to return the value of DescriptionAttributes, declared names, etc, etc.
I wrote a base class (RichEnum<>) to handle most fo the grunt work, which eases the above declaration of enums down to:
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);
}
}
The base class (RichEnum) is listed below.
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;
}
}
}
这篇关于我们可以在c#中定义枚举的隐式转换吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!