답변:
Description
System.ComponentModel 네임 스페이스 의 특성을 사용합니다 . 열거 형을 간단히 장식하십시오.
private enum PublishStatusValue
{
[Description("Not Completed")]
NotCompleted,
Completed,
Error
};
그런 다음이 코드를 사용하여 검색하십시오.
public static string GetDescription<T>(this T enumerationValue)
where T : struct
{
Type type = enumerationValue.GetType();
if (!type.IsEnum)
{
throw new ArgumentException("EnumerationValue must be of Enum type", "enumerationValue");
}
//Tries to find a DescriptionAttribute for a potential friendly name
//for the enum
MemberInfo[] memberInfo = type.GetMember(enumerationValue.ToString());
if (memberInfo != null && memberInfo.Length > 0)
{
object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs != null && attrs.Length > 0)
{
//Pull out the description value
return ((DescriptionAttribute)attrs[0]).Description;
}
}
//If we have no description attribute, just return the ToString of the enum
return enumerationValue.ToString();
}
ArgumentException
확장 방법 으로이 작업을 수행합니다.
public enum ErrorLevel
{
None,
Low,
High,
SoylentGreen
}
public static class ErrorLevelExtensions
{
public static string ToFriendlyString(this ErrorLevel me)
{
switch(me)
{
case ErrorLevel.None:
return "Everything is OK";
case ErrorLevel.Low:
return "SNAFU, if you know what I mean.";
case ErrorLevel.High:
return "Reaching TARFU levels";
case ErrorLevel.SoylentGreen:
return "ITS PEOPLE!!!!";
default:
return "Get your damn dirty hands off me you FILTHY APE!";
}
}
}
default
사례 구현이 반환 me.ToString()
하고 재정의하려는 열거 형 값에 대한 스위치 사례 문 만 제공하는 것이 좋습니다. 귀하의 예에서, 그것들은 모두 다르지만 실제 사용 사례에서는 대부분의 단일 단어 열거 형 값으로 충분하고 다중 단어 열거 형 값에 대한 재정의 만 제공 할 것으로 생각합니다.
어쩌면 누락 된 것이 있지만 Enum.GetName에 어떤 문제가 있습니까?
public string GetName(PublishStatusses value)
{
return Enum.GetName(typeof(PublishStatusses), value)
}
편집 : 사용자 친화적 인 문자열의 경우 .resource를 통해 국제화 / 현지화를 수행해야하며 데코레이터 속성보다 enum 키를 기반으로 고정 키를 사용하는 것이 더 좋습니다.
설명을 다시 열거 형 값으로 변환하는 역 확장 방법을 만들었습니다.
public static T ToEnumValue<T>(this string enumerationDescription) where T : struct
{
var type = typeof(T);
if (!type.IsEnum)
throw new ArgumentException("ToEnumValue<T>(): Must be of enum type", "T");
foreach (object val in System.Enum.GetValues(type))
if (val.GetDescription<T>() == enumerationDescription)
return (T)val;
throw new ArgumentException("ToEnumValue<T>(): Invalid description for enum " + type.Name, "enumerationDescription");
}
여기서 가장 쉬운 해결책은 사용자 지정 확장 방법을 사용하는 것입니다. (. NET 3.5 이상에서는 이전 프레임 워크 버전의 정적 도우미 메서드로 변환 할 수 있습니다).
public static string ToCustomString(this PublishStatusses value)
{
switch(value)
{
// Return string depending on value.
}
return null;
}
여기서는 열거 형 값의 실제 이름 이외의 것을 반환하려고한다고 가정합니다 (ToString을 호출하여 얻을 수 있음).
다른 게시물은 Java입니다. C #에서는 열거 형에 메서드를 넣을 수 없습니다.
다음과 같이하십시오.
PublishStatusses status = ...
String s = status.ToString();
열거 형 값에 다른 표시 값을 사용하려는 경우 특성 및 반사를 사용할 수 있습니다.
가장 간단한 방법은이 확장 클래스를 프로젝트에 포함시키는 것입니다. 프로젝트의 모든 열거 형과 함께 작동합니다.
public static class EnumExtensions
{
public static string ToFriendlyString(this Enum code)
{
return Enum.GetName(code.GetType(), code);
}
}
용법:
enum ExampleEnum
{
Demo = 0,
Test = 1,
Live = 2
}
...
ExampleEnum ee = ExampleEnum.Live;
Console.WriteLine(ee.ToFriendlyString());
string result = "Result: " + ee;
클래스 / 레퍼런스 타입을 피하는 다른 기본 옵션들 :
배열 방법
private struct PublishStatusses
{
public static string[] Desc = {
"Not Completed",
"Completed",
"Error"
};
public enum Id
{
NotCompleted = 0,
Completed,
Error
};
}
용법
string desc = PublishStatusses.Desc[(int)PublishStatusses.Id.Completed];
중첩 구조체 메소드
private struct PublishStatusses
{
public struct NotCompleted
{
public const int Id = 0;
public const string Desc = "Not Completed";
}
public struct Completed
{
public const int Id = 1;
public const string Desc = "Completed";
}
public struct Error
{
public const int Id = 2;
public const string Desc = "Error";
}
}
용법
int id = PublishStatusses.NotCompleted.Id;
string desc = PublishStatusses.NotCompleted.Desc;
업데이트 (2018 년 3 월 9 일)
확장 방법과 첫 번째 기술의 하이브리드.
나는 열거 형이 "그대로"있는 곳 (일반적인 전역 네임 스페이스가 아닌 출처에 가장 가깝게) 정의되는 것을 선호합니다.
namespace ViewModels
{
public class RecordVM
{
//public enum Enum { Minutes, Hours }
public struct Enum
{
public enum Id { Minutes, Hours }
public static string[] Name = { "Minute(s)", "Hour(s)" };
}
}
}
확장 방법은 공통 영역에 적합한 것으로 보이며 열거의 "현지화"정의로 확장 방법이 더 장황 해졌습니다.
namespace Common
{
public static class EnumExtensions
{
public static string Name(this RecordVM.Enum.Id id)
{
return RecordVM.Enum.Name[(int)id];
}
}
}
열거 형의 사용법 예제와 확장 방법입니다.
namespace Views
{
public class RecordView
{
private RecordDataFieldList<string, string> _fieldUnit;
public RecordView()
{
_fieldUnit.List = new IdValueList<string, string>
{
new ListItem<string>((int)RecordVM.Enum.Id.Minutes, RecordVM.Enum.Id.Minutes.Name()),
new ListItem<string>((int)RecordVM.Enum.Id.Hours, RecordVM.Enum.Id.Hours.Name())
};
}
private void Update()
{
RecordVM.Enum.Id eId = DetermineUnit();
_fieldUnit.Input.Text = _fieldUnit.List.SetSelected((int)eId).Value;
}
}
}
참고 : 실제로는 Enum
래퍼 (및 Name
배열) 를 제거하기로 결정했습니다 . 이름 문자열이 하드 코드 대신 리소스 (예 : 구성 파일 또는 DB)에서 오는 것이 가장 좋으며 확장 메소드를 ViewModels
네임 스페이스 (다른 "CommonVM.cs"파일에 있음) 게다가 모든 .Id
것이 산만하고 번거로워집니다.
namespace ViewModels
{
public class RecordVM
{
public enum Enum { Minutes, Hours }
//public struct Enum
//{
// public enum Id { Minutes, Hours }
// public static string[] Name = { "Minute(s)", "Hour(s)" };
//}
}
}
CommonVM.cs
//namespace Common
namespace ViewModels
{
public static class EnumExtensions
{
public static string Name(this RecordVM.Enum id)
{
//return RecordVM.Enum.Name[(int)id];
switch (id)
{
case RecordVM.Enum.Minutes: return "Minute(s)";
case RecordVM.Enum.Hours: return "Hour(s)";
default: return null;
}
}
}
}
열거 형의 사용법 예제와 확장 방법입니다.
namespace Views
{
public class RecordView
{
private RecordDataFieldList<string, string> _fieldUnit
public RecordView()
{
_fieldUnit.List = new IdValueList<string, string>
{
new ListItem<string>((int)RecordVM.Enum.Id.Minutes, RecordVM.Enum.Id.Minutes.Name()),
new ListItem<string>((int)RecordVM.Enum.Id.Hours, RecordVM.Enum.Id.Hours.Name())
};
}
private void Update()
{
RecordVM.Enum eId = DetermineUnit();
_fieldUnit.Input.Text = _fieldUnit.List.SetSelected((int)eId).Value;
}
}
}
Humanize Enums 가능성 과 함께 Humanizer 패키지를 사용할 수 있습니다 . 일축 :
enum PublishStatusses
{
[Description("Custom description")]
NotCompleted,
AlmostCompleted,
Error
};
그런 다음 Humanize
열거 형에서 확장 방법을 직접 사용할 수 있습니다.
var st1 = PublishStatusses.NotCompleted;
var str1 = st1.Humanize(); // will result in Custom description
var st2 = PublishStatusses.AlmostCompleted;
var str2 = st2.Humanize(); // will result in Almost completed (calculated automaticaly)
Ray Booysen과 관련하여 코드에 버그가 있습니다. 사용자 친화적 인 문자열이있는 Enum ToString
열거 형 값에 대한 여러 특성을 고려해야합니다.
public static string GetDescription<T>(this object enumerationValue)
where T : struct
{
Type type = enumerationValue.GetType();
if (!type.IsEnum)
{
throw new ArgumentException("EnumerationValue must be of Enum type", "enumerationValue");
}
//Tries to find a DescriptionAttribute for a potential friendly name
//for the enum
MemberInfo[] memberInfo = type.GetMember(enumerationValue.ToString());
if (memberInfo != null && memberInfo.Length > 0)
{
object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs != null && attrs.Length > 0 && attrs.Where(t => t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault() != null)
{
//Pull out the description value
return ((DescriptionAttribute)attrs.Where(t=>t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault()).Description;
}
}
//If we have no description attribute, just return the ToString of the enum
return enumerationValue.ToString();
public enum MyEnum
{
[Description("Option One")]
Option_One
}
public static string ToDescriptionString(this Enum This)
{
Type type = This.GetType();
string name = Enum.GetName(type, This);
MemberInfo member = type.GetMembers()
.Where(w => w.Name == name)
.FirstOrDefault();
DescriptionAttribute attribute = member != null
? member.GetCustomAttributes(true)
.Where(w => w.GetType() == typeof(DescriptionAttribute))
.FirstOrDefault() as DescriptionAttribute
: null;
return attribute != null ? attribute.Description : name;
}
this
호출 This
되는 것을 볼 수있는 확장 메소드 의 매개 변수 는 예외입니다 . 당신이 ( Enum Enum
) 와 같은 유형으로 그것을 호출 하면 코드를 읽을 수 없게 만듭니다.
열거 형을 사용하는 대신 정적 클래스를 사용하십시오.
바꾸다
private enum PublishStatuses{
NotCompleted,
Completed,
Error
};
와
private static class PublishStatuses{
public static readonly string NotCompleted = "Not Completed";
public static readonly string Completed = "Completed";
public static readonly string Error = "Error";
};
이처럼 사용됩니다
PublishStatuses.NotCompleted; // "Not Completed"
최고의 "확장 방법"솔루션을 사용하는 문제 :
개인 열거 형은 종종 다른 클래스 내에서 사용됩니다. 확장 메소드 솔루션은 자체 클래스에 있어야하므로 유효하지 않습니다. 이 솔루션은 개인용이며 다른 클래스에 포함될 수 있습니다.
VB.NET 팬이되었으므로 DescriptionAttribute 메서드와 확장 메서드를 결합한 버전이 있습니다. 먼저 결과는 다음과 같습니다.
Imports System.ComponentModel ' For <Description>
Module Module1
''' <summary>
''' An Enum type with three values and descriptions
''' </summary>
Public Enum EnumType
<Description("One")>
V1 = 1
' This one has no description
V2 = 2
<Description("Three")>
V3 = 3
End Enum
Sub Main()
' Description method is an extension in EnumExtensions
For Each v As EnumType In [Enum].GetValues(GetType(EnumType))
Console.WriteLine("Enum {0} has value {1} and description {2}",
v,
CInt(v),
v.Description
)
Next
' Output:
' Enum V1 has value 1 and description One
' Enum V2 has value 2 and description V2
' Enum V3 has value 3 and description Three
End Sub
End Module
기본 사항 : V1, V2 및 V3의 3 가지 값을 가진 EnumType이라는 열거 형. "마법"은 Sub Main ()의 Console.WriteLine 호출에서 발생하며, 마지막 인수는 단순히 v.Description
입니다. V1의 경우 "One", V2의 경우 "V2", V3의 경우 "Three"를 반환합니다. 이 Description-method는 실제로 EnumExtensions라는 다른 모듈에 정의 된 확장 메소드입니다.
Option Strict On
Option Explicit On
Option Infer Off
Imports System.Runtime.CompilerServices
Imports System.Reflection
Imports System.ComponentModel
Module EnumExtensions
Private _Descriptions As New Dictionary(Of String, String)
''' <summary>
''' This extension method adds a Description method
''' to all enum members. The result of the method is the
''' value of the Description attribute if present, else
''' the normal ToString() representation of the enum value.
''' </summary>
<Extension>
Public Function Description(e As [Enum]) As String
' Get the type of the enum
Dim enumType As Type = e.GetType()
' Get the name of the enum value
Dim name As String = e.ToString()
' Construct a full name for this enum value
Dim fullName As String = enumType.FullName + "." + name
' See if we have looked it up earlier
Dim enumDescription As String = Nothing
If _Descriptions.TryGetValue(fullName, enumDescription) Then
' Yes we have - return previous value
Return enumDescription
End If
' Find the value of the Description attribute on this enum value
Dim members As MemberInfo() = enumType.GetMember(name)
If members IsNot Nothing AndAlso members.Length > 0 Then
Dim descriptions() As Object = members(0).GetCustomAttributes(GetType(DescriptionAttribute), False)
If descriptions IsNot Nothing AndAlso descriptions.Length > 0 Then
' Set name to description found
name = DirectCast(descriptions(0), DescriptionAttribute).Description
End If
End If
' Save the name in the dictionary:
_Descriptions.Add(fullName, name)
' Return the name
Return name
End Function
End Module
사용하여 설명 속성을 Reflection
조회 하는 것이 느리기 때문에 조회도 개인용으로 캐시됩니다Dictionary
요청시 채워집니다.
(VB.NET 솔루션에 대해 죄송합니다. C #으로 변환하는 것이 상대적으로 쉽지만, 내 C #은 확장 프로그램과 같은 새로운 주제에 대해 녹슨 것입니다)
위의 제안을 샘플로 정리하십시오.
namespace EnumExtensions {
using System;
using System.Reflection;
public class TextAttribute : Attribute {
public string Text;
public TextAttribute( string text ) {
Text = text;
}//ctor
}// class TextAttribute
public static class EnumExtender {
public static string ToText( this Enum enumeration ) {
MemberInfo[] memberInfo = enumeration.GetType().GetMember( enumeration.ToString() );
if ( memberInfo != null && memberInfo.Length > 0 ) {
object[] attributes = memberInfo[ 0 ].GetCustomAttributes( typeof(TextAttribute), false );
if ( attributes != null && attributes.Length > 0 ) {
return ( (TextAttribute)attributes[ 0 ] ).Text;
}
}//if
return enumeration.ToString();
}//ToText
}//class EnumExtender
}//namespace
용법:
using System;
using EnumExtensions;
class Program {
public enum Appearance {
[Text( "left-handed" ) ]
Left,
[Text( "right-handed" ) ]
Right,
}//enum
static void Main( string[] args ) {
var appearance = Appearance.Left;
Console.WriteLine( appearance.ToText() );
}//Main
}//class
Enum.GetName 사용
위의 링크에서 ...
using System;
public class GetNameTest {
enum Colors { Red, Green, Blue, Yellow };
enum Styles { Plaid, Striped, Tartan, Corduroy };
public static void Main() {
Console.WriteLine("The 4th value of the Colors Enum is {0}", Enum.GetName(typeof(Colors), 3));
Console.WriteLine("The 4th value of the Styles Enum is {0}", Enum.GetName(typeof(Styles), 3));
}
}
// The example displays the following output:
// The 4th value of the Colors Enum is Yellow
// The 4th value of the Styles Enum is Corduroy
이 문서에 따르면 https://docs.microsoft.com/pt-br/dotnet/api/system.enum.tostring?view=netframework-4.8
다음과 같은 형식을 사용하여 열거자를 문자열로 변환하는 것이 가능합니다.
public enum Example
{
Example1,
Example2
}
Console.WriteLine(Example.Example1.ToString("g"));
//Outputs: "Example1"
이 링크에서 가능한 모든 형식을 볼 수 있습니다 : https://docs.microsoft.com/pt-br/dotnet/api/system.string?view=netframework-4.8
이것은 일반적인 GetCustomAttributes 메서드와 LINQ를 사용하여 일을 좀 더 깔끔하게 만드는 Ray Booysen 코드에 대한 업데이트입니다.
/// <summary>
/// Gets the value of the <see cref="T:System.ComponentModel.DescriptionAttribute"/> on an struct, including enums.
/// </summary>
/// <typeparam name="T">The type of the struct.</typeparam>
/// <param name="enumerationValue">A value of type <see cref="T:System.Enum"/></param>
/// <returns>If the struct has a Description attribute, this method returns the description. Otherwise it just calls ToString() on the struct.</returns>
/// <remarks>Based on http://stackoverflow.com/questions/479410/enum-tostring/479417#479417, but useful for any struct.</remarks>
public static string GetDescription<T>(this T enumerationValue) where T : struct
{
return enumerationValue.GetType().GetMember(enumerationValue.ToString())
.SelectMany(mi => mi.GetCustomAttributes<DescriptionAttribute>(false),
(mi, ca) => ca.Description)
.FirstOrDefault() ?? enumerationValue.ToString();
}
더 깔끔한 요약 :
using System;
using System.Reflection;
public class TextAttribute : Attribute
{
public string Text;
public TextAttribute(string text)
{
Text = text;
}
}
public static class EnumExtender
{
public static string ToText(this Enum enumeration)
{
var memberInfo = enumeration.GetType().GetMember(enumeration.ToString());
if (memberInfo.Length <= 0) return enumeration.ToString();
var attributes = memberInfo[0].GetCustomAttributes(typeof(TextAttribute), false);
return attributes.Length > 0 ? ((TextAttribute)attributes[0]).Text : enumeration.ToString();
}
}
밑줄과 동일한 사용법이 설명합니다.
다음을 포함하는 플래그 열거 형의 경우.
public static string Description(this Enum value)
{
Type type = value.GetType();
List<string> res = new List<string>();
var arrValue = value.ToString().Split(',').Select(v=>v.Trim());
foreach (string strValue in arrValue)
{
MemberInfo[] memberInfo = type.GetMember(strValue);
if (memberInfo != null && memberInfo.Length > 0)
{
object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs != null && attrs.Length > 0 && attrs.Where(t => t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault() != null)
{
res.Add(((DescriptionAttribute)attrs.Where(t => t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault()).Description);
}
else
res.Add(strValue);
}
else
res.Add(strValue);
}
return res.Aggregate((s,v)=>s+", "+v);
}
열거 형 / 설명 쌍을 저장하기 위해 일반 클래스를 사용하고 설명을 얻기 위해 중첩 된 도우미 클래스를 사용합니다.
열거 :
enum Status { Success, Fail, Pending }
일반 클래스 :
참고 : 일반 클래스는 열거 형 으로 제한 할 수 없으므로 대신 구조체로 제한 하고 생성자에서 열거 형 을 확인합니다 .
public class EnumX<T> where T : struct
{
public T Code { get; set; }
public string Description { get; set; }
public EnumX(T code, string desc)
{
if (!typeof(T).IsEnum) throw new NotImplementedException();
Code = code;
Description = desc;
}
public class Helper
{
private List<EnumX<T>> codes;
public Helper(List<EnumX<T>> codes)
{
this.codes = codes;
}
public string GetDescription(T code)
{
EnumX<T> e = codes.Where(c => c.Code.Equals(code)).FirstOrDefault();
return e is null ? "Undefined" : e.Description;
}
}
}
용법:
EnumX<Status>.Helper StatusCodes = new EnumX<Status>.Helper(new List<EnumX<Status>>()
{
new EnumX<Status>(Status.Success,"Operation was successful"),
new EnumX<Status>(Status.Fail,"Operation failed"),
new EnumX<Status>(Status.Pending,"Operation not complete. Please wait...")
});
Console.WriteLine(StatusCodes.GetDescription(Status.Pending));
완전히 사용자 정의 할 수있는 것을 원하면 여기에서 내 솔루션을 시도하십시오.
http://www.kevinwilliampang.com/post/Mapping-Enums-To-Strings-and-Strings-to-Enums-in-NET.aspx
기본적으로이 게시물에서는 Description 속성을 각 열거 형에 첨부하는 방법을 간략하게 설명하고 열거 형에서 설명으로 매핑하는 일반적인 방법을 제공합니다.