我正在尝试定义Enum
并添加用于CSV或类似文件的有效公共分隔符。然后我将它绑定到ComboBox
作为数据源,所以每当我从Enum定义中添加或删除时,我都不需要在组合框中更改任何内容。
问题是如何使用字符串表示来定义枚举,例如:
public enum SeparatorChars{Comma = ",", Tab = "\t", Space = " "}
答案 0 :(得分:96)
你不能 - 枚举值必须是整数值。您可以使用属性将字符串值与每个枚举值相关联,或者在这种情况下,如果每个分隔符都是单个字符,则可以使用char
值:
enum Separator
{
Comma = ',',
Tab = '\t',
Space = ' '
}
(编辑:只是为了澄清,你不能使char
枚举的基础类型,但你可以使用char
常量来分配对应于每个枚举值的整数值。上述枚举的类型为int
。)
如果你需要一个扩展方法:
public string ToSeparatorString(this Separator separator)
{
// TODO: validation
return ((char) separator).ToString();
}
答案 1 :(得分:69)
据我所知,您不会被允许为枚举分配字符串值。你可以做的是创建一个包含字符串常量的类。
public static class SeparatorChars
{
public static String Comma { get { return ",";} }
public static String Tab { get { return "\t,";} }
public static String Space { get { return " ";} }
}
答案 2 :(得分:50)
你可以实现它,但需要做一些工作。
public enum Test : int { [StringValue("a")] Foo = 1, [StringValue("b")] Something = 2 }
答案 3 :(得分:24)
您无法使用枚举执行此操作,但您可以这样做:
public static class SeparatorChars
{
public static string Comma = ",";
public static string Tab = "\t";
public static string Space = " ";
}
答案 4 :(得分:22)
对于字符串值(或任何其他类型)的简单枚举:
public static class MyEnumClass
{
public const string
MyValue1 = "My value 1",
MyValue2 = "My value 2";
}
用法:string MyValue = MyEnumClass.MyValue1;
答案 5 :(得分:12)
你不能,因为枚举只能基于原始数字类型。
您可以尝试使用Dictionary
代替:
Dictionary<String, char> separators = new Dictionary<string, char>
{
{"Comma", ','},
{"Tab", '\t'},
{"Space", ' '},
};
或者,您可以使用Dictionary<Separator, char>
或Dictionary<Separator, string>
,其中Separator
是正常的枚举:
enum Separator
{
Comma,
Tab,
Space
}
这比直接处理字符串更令人愉快。
答案 6 :(得分:9)
也许为时已晚,但是它来了。
我们可以使用属性EnumMember来管理Enum值。
public enum EUnitOfMeasure
{
[EnumMember(Value = "KM")]
Kilometer,
[EnumMember(Value = "MI")]
Miles
}
这样,EUnitOfMeasure的结果值为KM或MI。这也可以在安德鲁·惠特克answer中看到。
答案 7 :(得分:5)
可以按如下方式创建一个模拟枚举行为但使用string
代替int
的类...
public class GrainType
{
private string _typeKeyWord;
private GrainType(string typeKeyWord)
{
_typeKeyWord = typeKeyWord;
}
public override string ToString()
{
return _typeKeyWord;
}
public static GrainType Wheat = new GrainType("GT_WHEAT");
public static GrainType Corn = new GrainType("GT_CORN");
public static GrainType Rice = new GrainType("GT_RICE");
public static GrainType Barley = new GrainType("GT_BARLEY");
}
...用法
GrainType myGrain = GrainType.Wheat;
PrintGrainKeyword(myGrain);
...然后
public void PrintGrainKeyword(GrainType grain)
{
Console.Writeline("My Grain code is " + grain.ToString()); // Displays "My Grain code is GT_WHEAT"
}
答案 8 :(得分:5)
答案有点晚了,但也许将来会对某人有所帮助。我发现将struct用于此类问题更容易。
以下示例是从MS代码复制粘贴的部分:
namespace System.IdentityModel.Tokens.Jwt
{
//
// Summary:
// List of registered claims from different sources http://tools.ietf.org/html/rfc7519#section-4
// http://openid.net/specs/openid-connect-core-1_0.html#IDToken
public struct JwtRegisteredClaimNames
{
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string Actort = "actort";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string Typ = "typ";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string Sub = "sub";
//
// Summary:
// http://openid.net/specs/openid-connect-frontchannel-1_0.html#OPLogout
public const string Sid = "sid";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string Prn = "prn";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string Nbf = "nbf";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string Nonce = "nonce";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string NameId = "nameid";
}
}
答案 9 :(得分:2)
虽然真的不可能使用char
或string
作为枚举的基础,但我认为这不是你真正喜欢的。
就像你提到的那样,你想拥有一个可能性的枚举,并在一个组合框中显示这个字符串表示。如果用户选择其中一个字符串表示形式,则您希望获得相应的枚举。这是可能的:
首先,我们必须将一些字符串链接到枚举值。这可以使用DescriptionAttribute
来完成,就像描述here或here一样。
现在您需要创建枚举值列表和相应的描述。这可以通过使用以下方法来完成:
/// <summary>
/// Creates an List with all keys and values of a given Enum class
/// </summary>
/// <typeparam name="T">Must be derived from class Enum!</typeparam>
/// <returns>A list of KeyValuePair<Enum, string> with all available
/// names and values of the given Enum.</returns>
public static IList<KeyValuePair<T, string>> ToList<T>() where T : struct
{
var type = typeof(T);
if (!type.IsEnum)
{
throw new ArgumentException("T must be an enum");
}
return (IList<KeyValuePair<T, string>>)
Enum.GetValues(type)
.OfType<T>()
.Select(e =>
{
var asEnum = (Enum)Convert.ChangeType(e, typeof(Enum));
return new KeyValuePair<T, string>(e, asEnum.Description());
})
.ToArray();
}
现在,您将拥有所有枚举及其说明的键值对列表。因此,我们只需将其指定为组合框的数据源。
var comboBox = new ComboBox();
comboBox.ValueMember = "Key"
comboBox.DisplayMember = "Value";
comboBox.DataSource = EnumUtilities.ToList<Separator>();
comboBox.SelectedIndexChanged += (sender, e) =>
{
var selectedEnum = (Separator)comboBox.SelectedValue;
MessageBox.Show(selectedEnum.ToString());
}
用户可以看到枚举的所有字符串表示形式,并且在您的代码中,您将获得所需的枚举值。
答案 10 :(得分:2)
基于此处的一些答案,我实现了一个可重用的基类,该基类模仿枚举的行为,但以# This will work.
reviews.loc[idx[top_reviewers, 99, :], ['beer_name', 'brewer_id']]
# This will fail with TypeError "unhashable type: 'Index'".
reviews.loc[idx[top_reviewers, 99] , ['beer_name', 'brewer_id']]
# This fixes the problem. (pd.Index is not hashable, a tuple is.
# However, the problem matters only with the second expression.)
reviews.loc[idx[tuple(top_reviewers), 99] , ['beer_name', 'brewer_id']]
作为基础类型。它支持各种操作,包括:
string
,.Equals
和==
与其他实例进行比较这是全部的基类:
!=
这就是实现“字符串枚举”的方式:
public abstract class StringEnumBase<T> : IEquatable<T>
where T : StringEnumBase<T>
{
public string Value { get; }
protected StringEnumBase(string value) => this.Value = value;
public override string ToString() => this.Value;
public static List<T> AsList()
{
return typeof(T)
.GetProperties(BindingFlags.Public | BindingFlags.Static)
.Where(p => p.PropertyType == typeof(T))
.Select(p => (T)p.GetValue(null))
.ToList();
}
public static T Parse(string value)
{
List<T> all = AsList();
if (!all.Any(a => a.Value == value))
throw new InvalidOperationException($"\"{value}\" is not a valid value for the type {typeof(T).Name}");
return all.Single(a => a.Value == value);
}
public bool Equals(T other)
{
if (other == null) return false;
return this.Value == other?.Value;
}
public override bool Equals(object obj)
{
if (obj == null) return false;
if (obj is T other) return this.Equals(other);
return false;
}
public override int GetHashCode() => this.Value.GetHashCode();
public static bool operator ==(StringEnumBase<T> a, StringEnumBase<T> b) => a?.Equals(b) ?? false;
public static bool operator !=(StringEnumBase<T> a, StringEnumBase<T> b) => !(a?.Equals(b) ?? false);
public class JsonConverter<T> : Newtonsoft.Json.JsonConverter
where T : StringEnumBase<T>
{
public override bool CanRead => true;
public override bool CanWrite => true;
public override bool CanConvert(Type objectType) => ImplementsGeneric(objectType, typeof(StringEnumBase<>));
private static bool ImplementsGeneric(Type type, Type generic)
{
while (type != null)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == generic)
return true;
type = type.BaseType;
}
return false;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken item = JToken.Load(reader);
string value = item.Value<string>();
return StringEnumBase<T>.Parse(value);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value is StringEnumBase<T> v)
JToken.FromObject(v.Value).WriteTo(writer);
}
}
}
可以这样使用:
[JsonConverter(typeof(JsonConverter<Colour>))]
public class Colour : StringEnumBase<Colour>
{
private Colour(string value) : base(value) { }
public static Colour Red => new Colour("red");
public static Colour Green => new Colour("green");
public static Colour Blue => new Colour("blue");
}
我希望有人觉得这有用!
答案 11 :(得分:2)
对于那些来这里寻求更通用问题的答案的人,如果希望代码看起来像supportsUploading
,则可以扩展静态类的概念。
当您尚未完成所需的enum
且enum names
是enum values
的{{1}}表示形式时,以下方法适用。使用string
使重构更加简单。
enam name
这实现了具有字符串值(例如以下伪代码)的枚举的意图:
nameof()
答案 12 :(得分:2)
首先,您尝试分配字符串而不是字符,即使它们只是一个字符。使用','而不是“,”。接下来的事情是,enums只使用不带char
的整数类型,你可以使用unicode值,但我强烈建议你不要这样做。
如果您确定这些值保持不变,在不同的文化和语言中,我将使用带有const字符串的静态类。
答案 13 :(得分:1)
我创建了一个用于在.NET中创建字符串值枚举的基类。这只是一个C#文件,您可以将其复制并粘贴到项目中,也可以通过名为StringEnum的NuGet软件包进行安装。
///<completionlist cref="HexColor"/>
class HexColor : StringEnum<HexColor>
{
public static readonly HexColor Blue = New("#FF0000");
public static readonly HexColor Green = New("#00FF00");
public static readonly HexColor Red = New("#000FF");
}
// Static Parse Method
HexColor.Parse("#FF0000") // => HexColor.Red
HexColor.Parse("#ff0000", caseSensitive: false) // => HexColor.Red
HexColor.Parse("invalid") // => throws InvalidOperationException
// Static TryParse method.
HexColor.TryParse("#FF0000") // => HexColor.Red
HexColor.TryParse("#ff0000", caseSensitive: false) // => HexColor.Red
HexColor.TryParse("invalid") // => null
// Parse and TryParse returns the preexistent instances
object.ReferenceEquals(HexColor.Parse("#FF0000"), HexColor.Red) // => true
// Conversion from your `StringEnum` to `string`
string myString1 = HexColor.Red.ToString(); // => "#FF0000"
string myString2 = HexColor.Red; // => "#FF0000" (implicit cast)
<completitionlist>
进行注释,Intellisense将建议该枚举名称。 (在C#和VB中均可使用):即
要么:
.Net Standard 1.0
,因此可以在.Net Core
> = 1.0,.Net Framework
> = 4.5,Mono
>上运行= 4.6,等等。 public abstract class StringEnum<T> : IEquatable<T> where T : StringEnum<T>, new()
{
protected string Value;
private static IList<T> valueList = new List<T>();
protected static T New(string value)
{
if (value == null)
return null; // the null-valued instance is null.
var result = new T() { Value = value };
valueList.Add(result);
return result;
}
public static implicit operator string(StringEnum<T> enumValue) => enumValue.Value;
public override string ToString() => Value;
public static bool operator !=(StringEnum<T> o1, StringEnum<T> o2) => o1?.Value != o2?.Value;
public static bool operator ==(StringEnum<T> o1, StringEnum<T> o2) => o1?.Value == o2?.Value;
public override bool Equals(object other) => this.Value.Equals((other as T)?.Value ?? (other as string));
bool IEquatable<T>.Equals(T other) => this.Value.Equals(other.Value);
public override int GetHashCode() => Value.GetHashCode();
/// <summary>
/// Parse the <paramref name="value"/> specified and returns a valid <typeparamref name="T"/> or else throws InvalidOperationException.
/// </summary>
/// <param name="value">The string value representad by an instance of <typeparamref name="T"/>. Matches by string value, not by the member name.</param>
/// <param name="caseSensitive">If true, the strings must match case sensitivity.</param>
public static T Parse(string value, bool caseSensitive = false)
{
var result = TryParse(value, caseSensitive);
if (result == null)
throw new InvalidOperationException((value == null ? "null" : $"'{value}'") + $" is not a valid {typeof(T).Name}");
return result;
}
/// <summary>
/// Parse the <paramref name="value"/> specified and returns a valid <typeparamref name="T"/> or else returns null.
/// </summary>
/// <param name="value">The string value representad by an instance of <typeparamref name="T"/>. Matches by string value, not by the member name.</param>
/// <param name="caseSensitive">If true, the strings must match case sensitivity.</param>
public static T TryParse(string value, bool caseSensitive = false)
{
if (value == null) return null;
if (valueList.Count == 0) System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle); // force static fields initialization
var field = valueList.FirstOrDefault(f => f.Value.Equals(value,
caseSensitive ? StringComparison.Ordinal
: StringComparison.OrdinalIgnoreCase));
// Not using InvariantCulture because it's only supported in NETStandard >= 2.0
if (field == null)
return null;
return field;
}
}
Newtonsoft.Json
序列化支持,请复制此扩展版本。 StringEnum.cs 我意识到这个代码类似于Ben的回答。我从头开始真诚地写了它。但是我认为它有一些额外功能,例如<completitionlist>
hack,结果类看起来更像是枚举,没有在Parse(),NuGet包和repo上使用反射,希望能解决传入的问题和反馈
答案 14 :(得分:1)
我希望有一个更优雅的解决方案,比如在语言级别只允许字符串类型enum
,但似乎还不支持它。下面的代码与其他答案的想法基本相同,但我认为它更短并且可以重复使用。您所要做的就是在每个 [Description("")]
条目上方添加一个 enum
并添加一个具有 10 行的类。
班级:
public static class Extensions
{
public static string ToStringValue(this Enum en)
{
var type = en.GetType();
var memInfo = type.GetMember(en.ToString());
var attributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
var stringValue = ((DescriptionAttribute)attributes[0]).Description;
return stringValue;
}
}
用法:
enum Country
{
[Description("Deutschland")]
Germany,
[Description("Nippon")]
Japan,
[Description("Italia")]
Italy,
}
static void Main(string[] args)
{
Show(new[] {Country.Germany, Country.Japan, Country.Italy});
void Show(Country[] countries)
{
foreach (var country in countries)
{
Debug.WriteLine(country.ToStringValue());
}
}
}
答案 15 :(得分:0)
我们无法将枚举定义为字符串类型。枚举的已批准类型是byte,sbyte,short,ushort,int,uint,long或ulong。
如果您需要有关枚举的更多详细信息,请点击以下链接,该链接将帮助您了解枚举。 Enumeration
@ narendras1414
答案 16 :(得分:0)
对我有用。
public class ShapeTypes
{
private ShapeTypes() { }
public static string OVAL
{
get
{
return "ov";
}
private set { }
}
public static string SQUARE
{
get
{
return "sq";
}
private set { }
}
public static string RECTANGLE
{
get
{
return "rec";
}
private set { }
}
}
答案 17 :(得分:0)
我最近开始使用Tuples
public static (string Fox, string Rabbit, string Horse) Animals = ("Fox", "Rabbit", "Horse");
...
public static (string Comma, string Tab, string Space) SeparatorChars = (",", "\t", " ");
答案 18 :(得分:0)
添加更多内容,因为这里的一些答案缺少使用枚举的要点。自然的一种选择是将定义良好的字符串作为静态变量等,但随后您也为非法值打开了接口,即您需要验证输入。使用枚举可以保证只将允许的值传递给您的接口。
enum Separator
{
Comma,
Tab,
Space,
CRLF,
SoFunny
}
除此之外,您还可以使用例如用于映射目的的内部字典。
private readonly Dictionary<Separator, string> separatorMap = new Dictionary<Separator, string>()
{
{ Separator.Comma, "," },
{ Separator.Tab, "\t" },
{ Separator.Space, " " },
{ Separator.CRLF, "\r\n" },
{ Separator.SoFunny, "Your Mom" }
};
更复杂的方法是创建一个 static class 以赋予枚举新的功能并在那里处理映射。
使用上述代码的示例如下。
public string TransformToSingleString(List<string> values, Separator separator)
{
var separateWith = separatorMap[separator];
...
}
答案 19 :(得分:-1)
Enumaration Class
public sealed class GenericDateTimeFormatType
{
public static readonly GenericDateTimeFormatType Format1 = new GenericDateTimeFormatType("dd-MM-YYYY");
public static readonly GenericDateTimeFormatType Format2 = new GenericDateTimeFormatType("dd-MMM-YYYY");
private GenericDateTimeFormatType(string Format)
{
_Value = Format;
}
public string _Value { get; private set; }
}
Enumaration Consuption
public static void Main()
{
Country A = new Country();
A.DefaultDateFormat = GenericDateTimeFormatType.Format1;
Console.ReadLine();
}