Numaram aşağıdaki değerlerden oluşur:
private enum PublishStatusses{
NotCompleted,
Completed,
Error
};
Bu değerleri kullanıcı dostu bir şekilde verebilmek istiyorum.
Dize değer tekrar gitmek mümkün olması gerekmez.
Numaram aşağıdaki değerlerden oluşur:
private enum PublishStatusses{
NotCompleted,
Completed,
Error
};
Bu değerleri kullanıcı dostu bir şekilde verebilmek istiyorum.
Dize değer tekrar gitmek mümkün olması gerekmez.
Yanıtlar:
Description
System.ComponentModel ad alanından özniteliği kullanıyorum . Numaralandırmayı süsleyin:
private enum PublishStatusValue
{
[Description("Not Completed")]
NotCompleted,
Completed,
Error
};
Sonra almak için bu kodu kullanın:
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
gibi, yöntemin tamamen genel olması için bir neden yoktur.
Bunu uzantı yöntemleri ile yapıyorum:
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
vaka uygulamasının geri dönmesine izin vermek me.ToString()
ve yalnızca geçersiz kılmak istediğiniz numaralandırma değerleri için anahtar durum ifadeleri sağlamak daha iyidir . Örneğinizde, hepsinin farklı olduğunu anlıyorum, ancak gerçek kullanım durumlarında, tek kelimelik numaralandırma değerlerinin çoğunun yeterli olacağından ve yalnızca çok kelimeli numaralandırma değerleri için geçersiz kılmalar sağlayacağınızdan şüpheleniyorum.
Belki bir şey eksik, ama Enum.GetName ile sorun nedir?
public string GetName(PublishStatusses value)
{
return Enum.GetName(typeof(PublishStatusses), value)
}
edit: kullanıcı dostu dizeler için, uluslararasılaştırma / yerelleştirme yapmak için bir .resource geçmeniz gerekir ve aynı zamanda bir dekoratör özniteliği yerine enum anahtarına dayalı sabit bir anahtar kullanmak daha iyi olurdu.
Açıklamayı tekrar bir enum değerine dönüştürmek için bir ters uzantısı yöntemi oluşturdum:
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");
}
Buradaki en kolay çözüm, özel bir uzantı yöntemi kullanmaktır (en azından .NET 3.5'te - bunu önceki çerçeve sürümleri için statik bir yardımcı yönteme dönüştürebilirsiniz).
public static string ToCustomString(this PublishStatusses value)
{
switch(value)
{
// Return string depending on value.
}
return null;
}
Burada (sadece ToString çağırarak alabilirsiniz) enum değeri gerçek adı dışında bir şey döndürmek istediğiniz varsayıyorum.
Bu diğer yazı Java. C # 'daki Numaralandırmalara yöntem koyamazsınız.
sadece böyle bir şey yapın:
PublishStatusses status = ...
String s = status.ToString();
Numaralandırma değerleriniz için farklı görüntüleme değerleri kullanmak istiyorsanız, Öznitelikler ve Yansıma kullanabilirsiniz.
En basit yol sadece bu uzantı sınıfını projenize dahil etmektir, projedeki herhangi bir numaralandırma ile çalışacaktır:
public static class EnumExtensions
{
public static string ToFriendlyString(this Enum code)
{
return Enum.GetName(code.GetType(), code);
}
}
Kullanımı:
enum ExampleEnum
{
Demo = 0,
Test = 1,
Live = 2
}
...
ExampleEnum ee = ExampleEnum.Live;
Console.WriteLine(ee.ToFriendlyString());
string result = "Result: " + ee;
Sınıfları / referans türlerini önleyen bazı daha ilkel seçenekler:
Dizi yöntemi
private struct PublishStatusses
{
public static string[] Desc = {
"Not Completed",
"Completed",
"Error"
};
public enum Id
{
NotCompleted = 0,
Completed,
Error
};
}
kullanım
string desc = PublishStatusses.Desc[(int)PublishStatusses.Id.Completed];
İç içe yapı yöntemi
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";
}
}
kullanım
int id = PublishStatusses.NotCompleted.Id;
string desc = PublishStatusses.NotCompleted.Desc;
Güncelleme (03/09/2018)
Bir Genişleme Yöntemleri melezi ve yukarıdaki ilk teknik.
Enumların, "ait oldukları" (tanım kaynaklarına en yakın ve bazı ortak, küresel ad alanlarında değil) tanımlanmasını tercih ederim.
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)" };
}
}
}
Genişletme yöntemi ortak bir alan için uygun görünmektedir ve enumun "lokalize" tanımı artık genişletme yöntemini daha ayrıntılı hale getirmektedir.
namespace Common
{
public static class EnumExtensions
{
public static string Name(this RecordVM.Enum.Id id)
{
return RecordVM.Enum.Name[(int)id];
}
}
}
Enum ve onun uzatma yönteminin kullanım örneği.
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;
}
}
}
Not: Aslında Enum
sarıcı (ve Name
dizi) ortadan kaldırmaya karar verdim , çünkü isim dizelerinin sabit kodlu olmak yerine bir kaynaktan (yani config dosyası veya DB) gelmesi en iyisidir ve uzantı yöntemini ViewModels
ad alanı (yalnızca farklı bir "CommonVM.cs" dosyasında). Ayrıca her .Id
şey dikkat dağıtıcı ve hantal hale gelir.
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;
}
}
}
}
Enum ve onun uzatma yönteminin kullanım örneği.
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;
}
}
}
Humanizer paketini Humanize Enums olasılığı ile kullanabilirsiniz . Bir örnek:
enum PublishStatusses
{
[Description("Custom description")]
NotCompleted,
AlmostCompleted,
Error
};
Humanize
doğrudan numaralandırmada uzantı yöntemini kullanabilirsiniz :
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 ile ilgili olarak, kodda bir hata var: Kullanıcı dostu dizelerle Enum ToString
Enum değerlerinde birden çok özelliği hesaba katmanız gerekir.
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
çağrıldığını görebileceğiniz uzantı yöntemlerindeki parametredir This
. Bunu yaptığınız gibi çağırmak ( Enum Enum
) kodu daha az okunabilir hale getirir.
Bir enum kullanmak yerine statik bir sınıf kullanın.
değiştirmek
private enum PublishStatuses{
NotCompleted,
Completed,
Error
};
ile
private static class PublishStatuses{
public static readonly string NotCompleted = "Not Completed";
public static readonly string Completed = "Completed";
public static readonly string Error = "Error";
};
bu şekilde kullanılacak
PublishStatuses.NotCompleted; // "Not Completed"
En iyi "uzantı yöntemi" çözümlerini kullanarak sorun:
Özel bir numaralandırma genellikle başka bir sınıfın içinde kullanılır. Eklenti yöntemi çözümü, kendi sınıfında olması gerektiği için geçerli değildir. Bu çözüm özel olabilir ve başka bir sınıfa gömülebilir.
Bir VB.NET hayranı oldum, bu yüzden burada benim sürüm, DescriptionAttribute yöntemini bir uzantısı yöntemi ile birleştirerek. İlk olarak, sonuçlar:
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
Temel şeyler: Üç değer V1, V2 ve V3 olan EnumType adlı bir numaralandırma. "Büyü", son argümanın basit olduğu Sub Main () içindeki Console.WriteLine çağrısında gerçekleşir v.Description
. Bu, V1 için "Bir", V2 için "V2" ve V3 için "Üç" değerini döndürür. Bu Description-yöntemi aslında EnumExtensions adlı başka bir modülde tanımlanan bir genişletme yöntemidir:
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
Kullanarak açıklama özniteliklerine bakmak Reflection
yavaş olduğundan, aramalar özel olarak da önbelleğe alınır ve Dictionary
bu istek üzerine doldurulur.
(VB.NET çözümü için özür dilerim - C #'a çevirmek nispeten zor olmalı ve C # uzantıları gibi yeni konularda paslı)
Yukarıdaki önerilerin özetini örnekle temizleyin:
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
KULLANIM:
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 Kullan
Yukarıdaki linkten ...
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
Bu belgelere göre: https://docs.microsoft.com/pt-br/dotnet/api/system.enum.tostring?view=netframework-4.8
Aşağıdaki gibi bir format kullanarak bir numaralandırıcıyı dizeye dönüştürmek mümkündür:
public enum Example
{
Example1,
Example2
}
Console.WriteLine(Example.Example1.ToString("g"));
//Outputs: "Example1"
Olası tüm biçimleri bu bağlantıda görebilirsiniz: https://docs.microsoft.com/pt-br/dotnet/api/system.string?view=netframework-4.8
Bu, işleri biraz daha düzenli hale getirmek için genel GetCustomAttributes yöntemini ve LINQ kullanan Ray Booysen kodunun bir güncellemesidir.
/// <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();
}
Daha da temiz özet:
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();
}
}
Alt çizgi ile aynı kullanım açıklanmaktadır.
Bayraklar için numaralandırma dahil.
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 / açıklama çiftlerini depolamak için genel bir sınıf ve açıklamayı almak için iç içe bir yardımcı sınıf kullanın.
enum :
enum Status { Success, Fail, Pending }
Genel sınıf:
Not: Genel bir sınıf bir enum tarafından sınırlanamadığından, bunun yerine struct ile kısıtlıyorum ve yapıcıda enum'u kontrol ediyorum .
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;
}
}
}
Kullanımı:
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));
Sorununuzu çözmenin en iyi (ve en kolay) yolunun numaralandırmanız için bir Extension-Method yazmak olduğunu düşünüyorum:
public static string GetUserFriendlyString(this PublishStatusses status)
{
}
Tamamen özelleştirilebilir bir şey istiyorsanız, burada çözümümü deneyin:
http://www.kevinwilliampang.com/post/Mapping-Enums-To-Strings-and-Strings-to-Enums-in-NET.aspx
Temel olarak, yazı, numaralandırmalarınızın her birine Açıklama özniteliklerinin nasıl ekleneceğini açıklar ve numaralandırmadan açıklamaya eşlemek için genel bir yol sağlar.