การเป็นตัวแทนสตริงของ Enum


912

ฉันมีการแจงนับต่อไปนี้:

public enum AuthenticationMethod
{
    FORMS = 1,
    WINDOWSAUTHENTICATION = 2,
    SINGLESIGNON = 3
}

อย่างไรก็ตามปัญหาคือฉันต้องการคำว่า "FORMS" เมื่อฉันขอ AuthenticationMethod.FORMS ไม่ใช่ id 1

ฉันพบวิธีแก้ไขปัญหาต่อไปนี้สำหรับปัญหานี้ ( ลิงก์ ):

ก่อนอื่นฉันต้องสร้างแอตทริบิวต์ที่กำหนดเองชื่อ "StringValue":

public class StringValue : System.Attribute
{
    private readonly string _value;

    public StringValue(string value)
    {
        _value = value;
    }

    public string Value
    {
        get { return _value; }
    }

}

จากนั้นฉันสามารถเพิ่มคุณสมบัตินี้ในตัวแจงนับของฉัน:

public enum AuthenticationMethod
{
    [StringValue("FORMS")]
    FORMS = 1,
    [StringValue("WINDOWS")]
    WINDOWSAUTHENTICATION = 2,
    [StringValue("SSO")]
    SINGLESIGNON = 3
}

และแน่นอนฉันต้องการบางอย่างเพื่อดึงข้อมูล StringValue นั้น:

public static class StringEnum
{
    public static string GetStringValue(Enum value)
    {
        string output = null;
        Type type = value.GetType();

        //Check first in our cached results...

        //Look for our 'StringValueAttribute' 

        //in the field's custom attributes

        FieldInfo fi = type.GetField(value.ToString());
        StringValue[] attrs =
           fi.GetCustomAttributes(typeof(StringValue),
                                   false) as StringValue[];
        if (attrs.Length > 0)
        {
            output = attrs[0].Value;
        }

        return output;
    }
}

ตอนนี้ฉันมีเครื่องมือในการรับค่าสตริงสำหรับตัวระบุ ฉันสามารถใช้งานได้เช่นนี้:

string valueOfAuthenticationMethod = StringEnum.GetStringValue(AuthenticationMethod.FORMS);

ตอนนี้งานทั้งหมดนี้โอเคเหมือนมีเสน่ห์ แต่ฉันพบว่ามันทำงานได้มากมาย ฉันสงสัยว่ามีวิธีแก้ปัญหาที่ดีกว่านี้หรือไม่

ฉันยังลองกับพจนานุกรมและคุณสมบัติคงที่ แต่ก็ไม่ได้ดีขึ้นเช่นกัน


8
ดี! ฉันสามารถใช้สิ่งนี้เพื่อแปลค่า enum เป็นสตริงที่มีการแปล
Øyvind Skaar

5
ในขณะที่คุณอาจพบว่าสิ่งนี้ยืดยาว แต่จริง ๆ แล้วมันเป็นวิธีที่ยืดหยุ่นในการทำสิ่งอื่น ๆ ในฐานะที่เป็นหนึ่งในเพื่อนร่วมงานของฉันชี้ออกมานี้สามารถนำมาใช้ในหลาย ๆ กรณีที่จะเปลี่ยน Enum ช่วยว่ารหัสแผนที่ฐานข้อมูลเพื่อ ENUM ค่า ฯลฯ ...
BenAlabaster

27
คลาสแอ็ตทริบิวต์ส่วนต่อท้าย reccoments MSDN ด้วยส่วนต่อท้าย "Attribute" ดังนั้น "คลาส StringValueAttribute";)
serhio

14
ฉันเห็นด้วยกับ @BenAlabaster จริง ๆ แล้วมันค่อนข้างยืดหยุ่น นอกจากนี้คุณสามารถทำให้เป็นวิธีการขยายเพียงแค่เพิ่มthisไว้ข้างหน้าEnumในวิธีคงที่ของคุณ จากนั้นคุณสามารถทำได้ AuthenticationMethod.Forms.GetStringValue();
Justin Pihony

5
วิธีการนี้ใช้การไตร่ตรองเพื่ออ่านค่าแอททริบิวต์และมันช้ามากถ้าคุณต้องเรียกใช้ GetStringValue () หลายครั้งในประสบการณ์ของฉัน รูปแบบที่ปลอดภัยต่อ Enum นั้นเร็วกว่า
Rn222

คำตอบ:


868

ลองชนิดปลอดภัย-enumรูปแบบ

public sealed class AuthenticationMethod {

    private readonly String name;
    private readonly int value;

    public static readonly AuthenticationMethod FORMS = new AuthenticationMethod (1, "FORMS");
    public static readonly AuthenticationMethod WINDOWSAUTHENTICATION = new AuthenticationMethod (2, "WINDOWS");
    public static readonly AuthenticationMethod SINGLESIGNON = new AuthenticationMethod (3, "SSN");        

    private AuthenticationMethod(int value, String name){
        this.name = name;
        this.value = value;
    }

    public override String ToString(){
        return name;
    }

}

อัปเดต การแปลงประเภทอย่างชัดเจน (หรือโดยนัย) สามารถทำได้โดย

  • เพิ่มเขตข้อมูลคงที่ด้วยการแมป

    private static readonly Dictionary<string, AuthenticationMethod> instance = new Dictionary<string,AuthenticationMethod>();
    • nb เพื่อให้การเริ่มต้นของฟิลด์ "สมาชิก enum" ไม่ได้โยน NullReferenceException เมื่อเรียกตัวสร้างอินสแตนซ์ให้แน่ใจว่าได้ใส่ฟิลด์พจนานุกรมไว้ข้างหน้าฟิลด์ "สมาชิก enum" ในชั้นเรียนของคุณ นี่เป็นเพราะว่าตัวเริ่มต้นของฟิลด์แบบสแตติกถูกเรียกใช้ในลำดับการประกาศและก่อนตัวสร้างสแตติกการสร้างแบบแปลก ๆ และจำเป็น แต่สถานการณ์ที่สับสนซึ่งตัวสร้างอินสแตนซ์สามารถเรียกได้ก่อนที่ฟิลด์แบบสแตติกทั้งหมดจะถูกเตรียมใช้งาน
  • เติมการแมปนี้ในตัวสร้างอินสแตนซ์

    instance[name] = this;
  • และเพิ่มตัวดำเนินการแปลงชนิดที่ผู้ใช้กำหนด

    public static explicit operator AuthenticationMethod(string str)
    {
        AuthenticationMethod result;
        if (instance.TryGetValue(str, out result))
            return result;
        else
            throw new InvalidCastException();
    }

17
ดูเหมือนว่า enum แต่ไม่ใช่ enum ฉันสามารถจินตนาการได้ว่าก่อให้เกิดปัญหาที่น่าสนใจหากผู้คนเริ่มพยายามเปรียบเทียบ AuthenticationMethods คุณอาจต้องใช้ตัวดำเนินการความเท่าเทียมกันมากเกินไป
Ant

36
@Ant: ฉันไม่จำเป็นต้อง เนื่องจากเรามีเพียงหนึ่งอินสแตนซ์ของแต่ละ AuthenticationMethod การอ้างอิงความเท่าเทียมกันที่สืบทอดมาจาก Object จึงทำงานได้ดี
จาคุบŠturc

10
@tyriker: คอมไพเลอร์ทำ ตัวสร้างเป็นแบบส่วนตัวดังนั้นคุณจึงไม่สามารถสร้างอินสแตนซ์ใหม่ได้ สมาชิกแบบสแตติกยังไม่สามารถเข้าถึงได้ผ่านอินสแตนซ์
Jakub Šturc

21
@Jakub น่าสนใจมาก ฉันต้องเล่นกับมันเพื่อหาวิธีใช้มันและตระหนักถึงประโยชน์ของมัน เป็นคลาสสาธารณะไม่คงที่ แต่ไม่สามารถสร้างอินสแตนซ์ได้และคุณสามารถเข้าถึงสมาชิกแบบคงที่เท่านั้น โดยพื้นฐานแล้วมันจะทำตัวเหมือน Enum แต่ส่วนที่ดีที่สุด ... สมาชิกแบบคงที่จะถูกพิมพ์ของคลาสและไม่ใช่สตริงทั่วไปหรือ int มันคือ ... [รอสักครู่] ... พิมพ์ safe enum! ขอบคุณที่ช่วยฉันเข้าใจ
ต้มตุ๋น

6
@kiran ฉันได้โพสต์คำตอบของ Jakub Šturcรุ่นที่ปรับเปลี่ยนเล็กน้อยด้านล่างที่อนุญาตให้ใช้กับคำสั่ง Switch-Case ดังนั้นตอนนี้จึงไม่มีข้อเสียสำหรับวิธีการนี้ :)
deadlydog

228

ใช้วิธีการ

Enum.GetName(Type MyEnumType,  object enumvariable)  

ดังใน (สมมติว่าShipperเป็น Enum ที่กำหนดไว้)

Shipper x = Shipper.FederalExpress;
string s = Enum.GetName(typeof(Shipper), x);

มีพวงของวิธีการคงที่อื่น ๆ ในระดับ Enum มูลค่าการตรวจสอบด้วย ...


5
เผง ฉันสร้างแอตทริบิวต์ที่กำหนดเองสำหรับคำอธิบายสตริง แต่นั่นเป็นเพราะฉันต้องการรุ่นที่ใช้งานง่าย (มีช่องว่างและอักขระพิเศษอื่น ๆ ) ที่สามารถผูกกับ ComboBox ได้อย่างง่ายดาย
lc

5
Enum.GetName แสดงชื่อฟิลด์ใน enum - เหมือนกับ. ToString () หากประสิทธิภาพเป็นปัญหาอาจเป็นปัญหาได้ ฉันจะไม่กังวลเกี่ยวกับเรื่องนี้จนกว่าคุณจะแปลง enums มากมาย
Keith

8
ตัวเลือกอื่นที่ควรพิจารณาหากคุณต้องการ enum ที่มีหน้าที่เสริมเป็นพิเศษคือ "roll yr own" โดยใช้ struct ... คุณเพิ่มคุณสมบัติแบบคงที่ที่มีชื่อแบบอ่านอย่างเดียวเพื่อเป็นตัวแทนของค่า enum ที่เริ่มต้นกับคอนสตรัคเตอร์ ...
Charles Bretana

1
จากนั้นคุณสามารถเพิ่มสิ่งที่ struct สมาชิกอื่น ๆ ที่คุณต้องการที่จะใช้สิ่งที่คุณต้องการฟังก์ชั่นนี้ "enum" ที่จะมี ...
ชาร์ลส์ Bretana

2
ปัญหาที่นี่คือ GetName ไม่สามารถแปลเป็นภาษาท้องถิ่นได้ นั่นไม่ใช่ความกังวลเสมอไป แต่เป็นสิ่งที่ควรระวัง
Joel Coehoorn

79

คุณสามารถอ้างอิงชื่อแทนค่าโดยใช้ ToString ()

Console.WriteLine("Auth method: {0}", AuthenticationMethod.Forms.ToString());

เอกสารอยู่ที่นี่:

http://msdn.microsoft.com/en-us/library/16c1xs4z.aspx

... และถ้าคุณตั้งชื่อ enums ของคุณใน Pascal Case (อย่างที่ฉันทำ - เช่น ThisIsMyEnumValue = 1 ฯลฯ ) จากนั้นคุณสามารถใช้ regex ที่ง่ายมากในการพิมพ์แบบฟอร์มที่เป็นมิตร:

static string ToFriendlyCase(this string EnumString)
{
    return Regex.Replace(EnumString, "(?!^)([A-Z])", " $1");
}

ซึ่งสามารถเรียกได้ง่ายจากสตริงใด ๆ :

Console.WriteLine("ConvertMyCrazyPascalCaseSentenceToFriendlyCase".ToFriendlyCase());

ขาออก:

แปลงประโยคของฉัน Pascal บ้าเป็นกรณีที่เป็นมิตร

ที่บันทึกการวิ่งไปรอบ ๆ บ้านสร้างคุณสมบัติที่กำหนดเองและแนบกับ enums ของคุณหรือใช้ตารางการค้นหาเพื่อแต่งงานกับค่า enum ด้วยสตริงที่เป็นมิตรและที่ดีที่สุดของทั้งหมดมันเป็นการจัดการด้วยตนเองและสามารถใช้กับสตริง Pascal Case ใด ๆ นำมาใช้ใหม่มากขึ้น แน่นอนมันไม่อนุญาตให้คุณมีสิ่งที่แตกต่างชื่อที่เป็นมิตรที่จาก enum ที่โซลูชันของคุณมอบให้

ฉันชอบโซลูชันดั้งเดิมของคุณสำหรับสถานการณ์ที่ซับซ้อนกว่านี้ คุณสามารถนำโซลูชันของคุณไปอีกขั้นหนึ่งและทำให้ GetStringValue เป็นวิธีการเสริมของ enum ของคุณและจากนั้นคุณไม่จำเป็นต้องอ้างอิงเช่น StringEnum.GetStringValue ...

public static string GetStringValue(this AuthenticationMethod value)
{
  string output = null;
  Type type = value.GetType();
  FieldInfo fi = type.GetField(value.ToString());
  StringValue[] attrs = fi.GetCustomAttributes(typeof(StringValue), false) as StringValue[];
  if (attrs.Length > 0)
    output = attrs[0].Value;
  return output;
}

จากนั้นคุณสามารถเข้าถึงได้โดยตรงจากอินสแตนซ์ enum ของคุณ:

Console.WriteLine(AuthenticationMethod.SSO.GetStringValue());

2
สิ่งนี้ไม่ได้ช่วยหาก "ชื่อที่จำง่าย" ต้องการช่องว่าง เช่น "การรับรองความถูกต้องของฟอร์ม"
Ray Booysen

4
ดังนั้นตรวจสอบให้แน่ใจว่า enum ตั้งชื่อด้วยตัวพิมพ์ใหญ่เช่น FormsAuthentication และแทรกช่องว่างก่อนตัวพิมพ์ใหญ่ใด ๆ ที่ไม่ได้อยู่ที่จุดเริ่มต้น มันไม่ได้เป็นวิทยาศาสตร์จรวดเพื่อแทรกช่องว่างในสตริง ...
BenAlabaster

4
การเว้นวรรคอัตโนมัติของชื่อ Pascal Case มีปัญหาหากมีตัวย่อที่ควรเป็นตัวพิมพ์ใหญ่, XML หรือ GPS เป็นต้น
Richard Ev

2
@RichardEv ไม่มี regex ที่สมบูรณ์แบบสำหรับเรื่องนี้ แต่นี่คือสิ่งที่ควรจะทำงานได้ดีขึ้นเล็กน้อยด้วยตัวย่อ "(?!^)([^A-Z])([A-Z])", "$1 $2". ดังนั้นHereIsATESTHere Is ATESTจะกลายเป็น
Sparebytes

ไม่สง่างามที่ทำ "แฮ็ก" เล็กน้อยเหล่านี้ซึ่งเป็นสิ่งที่พวกเขา ฉันได้สิ่งที่ OP พูดและพยายามหาวิธีแก้ปัญหาที่คล้ายกันนั่นคือใช้ความหรูหราของ Enums แต่สามารถเข้าถึงข้อความที่เกี่ยวข้องได้อย่างง่ายดาย ทางออกเดียวที่ฉันคิดได้คือการใช้การแมปบางอย่างระหว่างชื่อ enum และค่าสตริง แต่นั่นไม่ได้ทำให้เกิดปัญหาในการดูแลรักษาข้อมูลสตริง (แต่ทำให้เหมาะสำหรับสถานการณ์ที่คุณต้องมีหลายภูมิภาคเป็นต้น )
Tahir Khalid

72

น่าเสียดายที่การสะท้อนถึงคุณลักษณะของ enums ค่อนข้างช้า:

ดูคำถามนี้: ทุกคนรู้วิธีที่รวดเร็วในการเข้าถึงแอตทริบิวต์ที่กำหนดเองในค่า enum หรือไม่

.ToString()ค่อนข้างช้า enums เกินไป

คุณสามารถเขียนวิธีการขยายสำหรับ enums แม้ว่า:

public static string GetName( this MyEnum input ) {
    switch ( input ) {
        case MyEnum.WINDOWSAUTHENTICATION:
            return "Windows";
        //and so on
    }
}

สิ่งนี้ไม่ดี แต่จะรวดเร็วและไม่ต้องการการสะท้อนสำหรับแอตทริบิวต์หรือชื่อฟิลด์


อัปเดต C # 6

หากคุณสามารถใช้ C # 6 แล้วใหม่nameofผู้ประกอบการทำงานสำหรับ enums ดังนั้นnameof(MyEnum.WINDOWSAUTHENTICATION)จะถูกแปลงเป็น"WINDOWSAUTHENTICATION"ที่รวบรวมเวลาทำให้มันเป็นวิธีที่เร็วที่สุดที่จะได้รับชื่อ enum

โปรดทราบว่าสิ่งนี้จะแปลงค่า enum อย่างชัดเจนเป็นค่าคงที่แบบอินไลน์ดังนั้นจึงใช้ไม่ได้กับค่า enum ที่คุณมีในตัวแปร ดังนั้น:

nameof(AuthenticationMethod.FORMS) == "FORMS"

แต่...

var myMethod = AuthenticationMethod.FORMS;
nameof(myMethod) == "myMethod"

24
คุณสามารถดึงค่าแอททริบิวต์หนึ่งครั้งและวางไว้ในพจนานุกรม <MyEnum, สตริง> เพื่อคงลักษณะการประกาศ
Jon Skeet

1
ใช่นั่นคือสิ่งที่เราลงเอยด้วยการทำแอพด้วยจำนวนเงินมากมายเมื่อเราพบว่าภาพสะท้อนนั้นเป็นคอขวด
Keith

ขอบคุณ Jon และ Keith ฉันลงเอยด้วยการใช้คำแนะนำพจนานุกรมของคุณ ใช้งานได้ดี (และรวดเร็ว!)
Helge Klein

@ JonSkeet ฉันรู้ว่านี่เก่าแล้ว แต่เราจะทำสิ่งนี้ให้สำเร็จได้อย่างไร?
user919426

2
@ user919426: บรรลุต้องการหรือไม่ วางไว้ในพจนานุกรมหรือไม่ เพียงสร้างพจนานุกรมโดยมีตัวเตรียมการเริ่มต้นเก็บรวบรวม ... ยังไม่ชัดเจนว่าคุณต้องการอะไร
Jon Skeet

59

ฉันใช้วิธีการขยาย:

public static class AttributesHelperExtension
    {
        public static string ToDescription(this Enum value)
        {
            var da = (DescriptionAttribute[])(value.GetType().GetField(value.ToString())).GetCustomAttributes(typeof(DescriptionAttribute), false);
            return da.Length > 0 ? da[0].Description : value.ToString();
        }
}

ตอนนี้ตกแต่งenumด้วย:

public enum AuthenticationMethod
{
    [Description("FORMS")]
    FORMS = 1,
    [Description("WINDOWSAUTHENTICATION")]
    WINDOWSAUTHENTICATION = 2,
    [Description("SINGLESIGNON ")]
    SINGLESIGNON = 3
}

เมื่อคุณโทรมา

AuthenticationMethod.FORMS.ToDescription()"FORMS"คุณจะได้รับ


1
ฉันต้องเพิ่มusing System.ComponentModel;ด้วยวิธีนี้ใช้ได้เฉพาะถ้าคุณต้องการให้ค่า String เป็นชื่อเดียวกับชื่อของ Enum OP ต้องการค่าที่แตกต่าง
elcool

2
คุณไม่ได้หมายความว่าคุณโทรมา AuthenticationMethod.FORMS.ToDescription()เหรอ?
nicodemus13

41

เพียงใช้ToString()วิธีการ

public enum any{Tomato=0,Melon,Watermelon}

เพื่ออ้างอิงสตริงTomatoเพียงใช้

any.Tomato.ToString();

ว้าว. นั่นเป็นเรื่องง่าย ฉันรู้ว่า OP ต้องการเพิ่มคำอธิบายสตริงที่กำหนดเอง แต่นี่คือสิ่งที่ฉันต้องการ ฉันควรจะรู้ลองดูย้อนหลัง แต่ฉันลงเส้นทาง Enum.GetName
Rafe

7
ทำไมคนอื่นถึงทำสิ่งนี้มากเกินไป?
เบรนต์

18
@Brent เนื่องจากบ่อยครั้งที่คุณมี.ToString()ค่าแตกต่างจากค่าที่ใช้งานง่ายที่คุณต้องการ
Novitchi S

2
@Brent - เพราะนี่แตกต่างจากคำถามที่ถูกถาม คำถามที่ถามคือวิธีรับสตริงนี้จากตัวแปรที่กำหนดค่าที่แจกแจง นั่นเป็นแบบไดนามิกในเวลาทำงาน นี่คือการตรวจสอบคำจำกัดความของประเภทและตั้งค่าในเวลาทำงาน
โฮแกน

1
@Hogan - ToString () ทำงานกับตัวแปรได้ดี: any fruit = any.Tomato; string tomato = fruit.ToString();
LiborV

29

วิธีแก้ปัญหานี้ง่ายมากด้วย. Net 4.0 ขึ้นไป ไม่จำเป็นต้องใช้รหัสอื่น

public enum MyStatus
{
    Active = 1,
    Archived = 2
}

ในการรับสตริงเกี่ยวกับการใช้เพียงแค่:

MyStatus.Active.ToString("f");

หรือ

MyStatus.Archived.ToString("f");`

ค่าจะเป็น "ใช้งานอยู่" หรือ "เก็บถาวร"

หากต้องการดูรูปแบบสตริงที่แตกต่าง ("f" จากด้านบน) เมื่อมีการโทรEnum.ToStringดูหน้านี้Strings Format Format


28

ฉันใช้คุณลักษณะคำอธิบายจากเนมสเปซ System.ComponentModel เพียงตกแต่ง enum แล้วใช้รหัสนี้เพื่อดึงข้อมูล:

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)
                {
                    //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();

        }

ตัวอย่างเช่น:

public enum Cycle : int
{        
   [Description("Daily Cycle")]
   Daily = 1,
   Weekly,
   Monthly
}

รหัสนี้เหมาะสำหรับ enums ที่คุณไม่ต้องการ "ชื่อที่จำง่าย" และจะคืนค่า. ToString () ของ enum


27

ฉันชอบคำตอบของจาคุบ urturc จริง ๆ แต่ข้อบกพร่องคือคุณไม่สามารถใช้มันกับคำสั่งสลับตัวพิมพ์เล็ก - ใหญ่ได้ ต่อไปนี้เป็นคำตอบที่แก้ไขเล็กน้อยซึ่งสามารถใช้กับคำสั่ง switch ได้:

public sealed class AuthenticationMethod
{
    #region This code never needs to change.
    private readonly string _name;
    public readonly Values Value;

    private AuthenticationMethod(Values value, String name){
        this._name = name;
        this.Value = value;
    }

    public override String ToString(){
        return _name;
    }
    #endregion

    public enum Values
    {
        Forms = 1,
        Windows = 2,
        SSN = 3
    }

    public static readonly AuthenticationMethod FORMS = new AuthenticationMethod (Values.Forms, "FORMS");
    public static readonly AuthenticationMethod WINDOWSAUTHENTICATION = new AuthenticationMethod (Values.Windows, "WINDOWS");
    public static readonly AuthenticationMethod SINGLESIGNON = new AuthenticationMethod (Values.SSN, "SSN");
}

ดังนั้นคุณจะได้รับประโยชน์ทั้งหมดจากคำตอบของ Jakub Šturcรวมทั้งเราสามารถใช้มันกับคำสั่ง switch ดังนี้:

var authenticationMethodVariable = AuthenticationMethod.FORMS;  // Set the "enum" value we want to use.
var methodName = authenticationMethodVariable.ToString();       // Get the user-friendly "name" of the "enum" value.

// Perform logic based on which "enum" value was chosen.
switch (authenticationMethodVariable.Value)
{
    case authenticationMethodVariable.Values.Forms: // Do something
        break;
    case authenticationMethodVariable.Values.Windows: // Do something
        break;
    case authenticationMethodVariable.Values.SSN: // Do something
        break;      
}

วิธีแก้ปัญหาที่สั้นกว่าคือการลบ enums {} และเก็บจำนวนคงที่ของจำนวน Enums ที่คุณสร้างขึ้นแทน สิ่งนี้ยังให้ประโยชน์ที่คุณไม่ต้องเพิ่มอินสแตนซ์ใหม่ที่คุณทำในรายการ enum เช่นpublic static int nextAvailable { get; private set; }นั้นในตัวสร้างthis.Value = nextAvailable++;
kjhf

แนวคิดที่น่าสนใจ @kjhf ความกังวลของฉันจะเป็นอย่างไรหากมีคนเรียงลำดับรหัสใหม่ค่าที่กำหนดให้กับค่า enum อาจเปลี่ยนแปลงได้เช่นกัน ตัวอย่างเช่นสิ่งนี้อาจส่งผลให้เกิดค่า enum ที่ไม่ถูกต้องเมื่อบันทึกค่า enum ลงในไฟล์ / ฐานข้อมูลลำดับของบรรทัด "new AuthenticationMethod (... )" จะเปลี่ยนไป (เช่นถูกลบ) แล้ว เรียกใช้แอปอีกครั้งและดึงค่า enum จากไฟล์ / ฐานข้อมูล ค่า enum อาจไม่ตรงกับ AuthenticationMethod ที่ถูกบันทึกไว้ตั้งแต่แรก
deadlydog

จุดดี - แม้ว่าฉันหวังว่าในกรณีเหล่านี้ผู้คนจะไม่พึ่งพาค่าจำนวนเต็มของ enum (หรือเรียงลำดับรหัส enum) - และค่านี้ใช้เป็นสวิตช์และอาจเป็นทางเลือกแทน. Equal () และ GetHashCode () หากคุณกังวลคุณสามารถแสดงความคิดเห็นอย่างมากกับ "ห้ามผู้อ้างอิง": p
kjhf

คุณไม่สามารถโอเวอร์โหลด=โอเปอเรเตอร์เพื่อให้สวิตช์ทำงานได้หรือไม่ ฉันทำสิ่งนี้ใน VB และสามารถใช้งานได้ในselect caseแถลงการณ์
user1318499

@ user1318499 ไม่ C # มีกฎที่เข้มงวดกว่าคำสั่ง switch กว่า VB คุณไม่สามารถใช้คลาสอินสแตนซ์สำหรับคำสั่ง Case; คุณสามารถใช้ primitives คงที่เท่านั้น
deadlydog

13

ฉันใช้ชุดค่าผสมของข้อเสนอแนะหลายข้อรวมกับแคชบางส่วน ตอนนี้ฉันได้ความคิดจากโค้ดบางอย่างที่ฉันพบที่ไหนสักแห่งในเน็ต แต่ฉันจำไม่ได้ว่าอยู่ที่ไหนฉันหามันเจอ ดังนั้นหากใครเคยพบบางสิ่งที่มีลักษณะคล้ายกันโปรดแสดงความคิดเห็นพร้อมกับการระบุแหล่งที่มา

อย่างไรก็ตามการใช้งานเกี่ยวข้องกับตัวแปลงประเภทดังนั้นหากคุณเชื่อมโยงกับ UI มันจะ 'ใช้ได้' คุณสามารถขยายด้วยรูปแบบของ Jakub สำหรับการค้นหารหัสอย่างรวดเร็วโดยการเริ่มต้นจากตัวแปลงชนิดเป็นวิธีคงที่

การใช้ฐานจะมีลักษณะเช่นนี้

[TypeConverter(typeof(CustomEnumTypeConverter<MyEnum>))]
public enum MyEnum
{
    // The custom type converter will use the description attribute
    [Description("A custom description")]
    ValueWithCustomDescription,

   // This will be exposed exactly.
   Exact
}

รหัสสำหรับตัวแปลงประเภท enum ที่กำหนดเองมีดังนี้:

public class CustomEnumTypeConverter<T> : EnumConverter
    where T : struct
{
    private static readonly Dictionary<T,string> s_toString = 
      new Dictionary<T, string>();

    private static readonly Dictionary<string, T> s_toValue = 
      new Dictionary<string, T>();

    private static bool s_isInitialized;

    static CustomEnumTypeConverter()
    {
        System.Diagnostics.Debug.Assert(typeof(T).IsEnum,
          "The custom enum class must be used with an enum type.");
    }

    public CustomEnumTypeConverter() : base(typeof(T))
    {
        if (!s_isInitialized)
        {
            Initialize();
            s_isInitialized = true;
        }
    }

    protected void Initialize()
    {
        foreach (T item in Enum.GetValues(typeof(T)))
        {
            string description = GetDescription(item);
            s_toString[item] = description;
            s_toValue[description] = item;
        }
    }

    private static string GetDescription(T optionValue)
    {
        var optionDescription = optionValue.ToString();
        var optionInfo = typeof(T).GetField(optionDescription);
        if (Attribute.IsDefined(optionInfo, typeof(DescriptionAttribute)))
        {
            var attribute = 
              (DescriptionAttribute)Attribute.
                 GetCustomAttribute(optionInfo, typeof(DescriptionAttribute));
            return attribute.Description;
        }
        return optionDescription;
    }

    public override object ConvertTo(ITypeDescriptorContext context, 
       System.Globalization.CultureInfo culture, 
       object value, Type destinationType)
    {
        var optionValue = (T)value;

        if (destinationType == typeof(string) && 
            s_toString.ContainsKey(optionValue))
        {
            return s_toString[optionValue];
        }

        return base.ConvertTo(context, culture, value, destinationType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, 
       System.Globalization.CultureInfo culture, object value)
    {
        var stringValue = value as string;

        if (!string.IsNullOrEmpty(stringValue) && s_toValue.ContainsKey(stringValue))
        {
            return s_toValue[stringValue];
        }

        return base.ConvertFrom(context, culture, value);
    }
}

}


12

ในคำถามของคุณคุณไม่เคยพูดว่าคุณต้องการค่าตัวเลขของ enum จริงทุกที่

หากคุณไม่ต้องการเพียงแค่ enum ของสตริงประเภท (ซึ่งไม่ใช่ประเภทอินทิกรัลดังนั้นไม่สามารถเป็นฐานของ enum) นี่เป็นวิธี:

    static class AuthenticationMethod
    {
        public static readonly string
            FORMS = "Forms",
            WINDOWSAUTHENTICATION = "WindowsAuthentication";
    }

คุณสามารถใช้ไวยากรณ์เดียวกับ enum เพื่ออ้างอิงได้

if (bla == AuthenticationMethod.FORMS)

มันจะช้ากว่าค่าตัวเลขเล็กน้อย (เปรียบเทียบสตริงแทนตัวเลข) แต่ในด้านบวกจะไม่ใช้การสะท้อน (ช้า) เพื่อเข้าถึงสตริง


ถ้าคุณใช้ "const" แทน "static readonly" คุณสามารถใช้ค่าเป็นเลเบล case ในคำสั่ง switch
Ed N.

11

ฉันจะแก้ไขสิ่งนี้เป็นวิธีส่วนขยายได้อย่างไร:

using System.ComponentModel;
public static string GetDescription(this Enum value)
{
    var descriptionAttribute = (DescriptionAttribute)value.GetType()
        .GetField(value.ToString())
        .GetCustomAttributes(false)
        .Where(a => a is DescriptionAttribute)
        .FirstOrDefault();

    return descriptionAttribute != null ? descriptionAttribute.Description : value.ToString();
}

enum:

public enum OrderType
{
    None = 0,
    [Description("New Card")]
    NewCard = 1,
    [Description("Reload")]
    Refill = 2
}

การใช้งาน (โดยที่ o.OrderType เป็นคุณสมบัติที่มีชื่อเหมือนกับ enum):

o.OrderType.GetDescription()

ซึ่งทำให้ฉันมีสตริงของ "บัตรใหม่" หรือ "โหลดใหม่" แทนค่า enum ที่แท้จริงของ NewCard และ Refill


เพื่อความสมบูรณ์คุณควรแนบสำเนาคลาส DescriptionAttribute ของคุณ
เบอร์นีไวท์

3
เบอร์นีรายละเอียด
แอ็ตทริบิวต์

11

ปรับปรุง:ไปที่หน้านี้ในอีก 8 ปีต่อมาหลังจากไม่ได้สัมผัส C # เป็นเวลานานดูเหมือนว่าคำตอบของฉันจะไม่ใช่ทางออกที่ดีที่สุดอีกต่อไป ฉันชอบโซลูชันตัวแปลงที่เชื่อมโยงกับคุณลักษณะของฟังก์ชัน

หากคุณอ่านข้อความนี้โปรดตรวจสอบคำตอบอื่น ๆ
(คำใบ้: พวกเขาอยู่เหนือคนนี้)


ในฐานะส่วนใหญ่ของคุณฉันชอบคำตอบที่เลือกโดย Jakub Šturcแต่ฉันก็เกลียดที่จะคัดลอกรหัสวางและพยายามทำให้น้อยที่สุดเท่าที่จะทำได้

ดังนั้นฉันจึงตัดสินใจว่าฉันต้องการคลาส EnumBase ซึ่งฟังก์ชันการทำงานส่วนใหญ่ได้รับการสืบทอด / ติดตั้งไว้ภายในทำให้ฉันต้องให้ความสำคัญกับเนื้อหาแทนที่จะเป็นพฤติกรรม

ปัญหาหลักของวิธีการนี้ขึ้นอยู่กับข้อเท็จจริงที่ว่าแม้ว่าค่า Enum จะเป็นประเภทที่ปลอดภัยสำหรับการโต้ตอบ แต่การโต้ตอบก็คือการใช้งานแบบคงที่ของประเภท Enum ดังนั้นด้วยความช่วยเหลือของเวทมนตร์ทั่วไปฉันคิดว่าในที่สุดฉันก็ได้ส่วนผสมที่ถูกต้อง หวังว่าบางคนจะพบว่าสิ่งนี้มีประโยชน์อย่างที่ฉันทำ

ฉันจะเริ่มต้นด้วยตัวอย่างของ Jakub แต่ใช้การสืบทอดและชื่อสามัญ:

public sealed class AuthenticationMethod : EnumBase<AuthenticationMethod, int>
{
    public static readonly AuthenticationMethod FORMS =
        new AuthenticationMethod(1, "FORMS");
    public static readonly AuthenticationMethod WINDOWSAUTHENTICATION =
        new AuthenticationMethod(2, "WINDOWS");
    public static readonly AuthenticationMethod SINGLESIGNON =
        new AuthenticationMethod(3, "SSN");

    private AuthenticationMethod(int Value, String Name)
        : base( Value, Name ) { }
    public new static IEnumerable<AuthenticationMethod> All
    { get { return EnumBase<AuthenticationMethod, int>.All; } }
    public static explicit operator AuthenticationMethod(string str)
    { return Parse(str); }
}

และนี่คือคลาสฐาน:

using System;
using System.Collections.Generic;
using System.Linq; // for the .AsEnumerable() method call

// E is the derived type-safe-enum class
// - this allows all static members to be truly unique to the specific
//   derived class
public class EnumBase<E, T> where E: EnumBase<E, T>
{
    #region Instance code
    public T Value { get; private set; }
    public string Name { get; private set; }

    protected EnumBase(T EnumValue, string Name)
    {
        Value = EnumValue;
        this.Name = Name;
        mapping.Add(Name, this);
    }

    public override string ToString() { return Name; }
    #endregion

    #region Static tools
    static private readonly Dictionary<string, EnumBase<E, T>> mapping;
    static EnumBase() { mapping = new Dictionary<string, EnumBase<E, T>>(); }
    protected static E Parse(string name)
    {
        EnumBase<E, T> result;
        if (mapping.TryGetValue(name, out result))
        {
            return (E)result;
        }

        throw new InvalidCastException();
    }
    // This is protected to force the child class to expose it's own static
    // method.
    // By recreating this static method at the derived class, static
    // initialization will be explicit, promising the mapping dictionary
    // will never be empty when this method is called.
    protected static IEnumerable<E> All
    { get { return mapping.Values.AsEnumerable().Cast<E>(); } }
    #endregion
}

คุณอาจจะเรียกตัวสร้างสแตติกที่ได้รับมาจากตัวสร้างสแตติกฐาน ฉันยังคงมองหามัน แต่จนถึงขณะนี้ฉันไม่พบปัญหาใด ๆ กับมัน: stackoverflow.com/questions/55290034/ …
Cory-G

10

ฉันเห็นด้วยกับ Keith แต่ฉันไม่สามารถลงคะแนนได้ (ยัง)

ฉันใช้วิธีการคงที่และคำสั่งคุณภาพชั้นหนึ่งเพื่อกลับสิ่งที่ฉันต้องการ ในฐานข้อมูลฉันเก็บ Tinyint และรหัสของฉันใช้ enum จริงเท่านั้นดังนั้นสตริงสำหรับความต้องการของ UI หลังจากการทดสอบจำนวนมากสิ่งนี้ส่งผลให้เกิดประสิทธิภาพที่ดีที่สุดและควบคุมผลลัพธ์ได้มากที่สุด

public static string ToSimpleString(this enum)
{
     switch (enum)
     {
         case ComplexForms:
             return "ComplexForms";
             break;
     }
}

public static string ToFormattedString(this enum)
{
     switch (enum)
     {
         case ComplexForms:
             return "Complex Forms";
             break;
     }
}

อย่างไรก็ตามโดยบางบัญชีสิ่งนี้นำไปสู่ฝันร้ายในการบำรุงรักษาที่อาจเกิดขึ้นและกลิ่นของรหัส ฉันพยายามที่จะจับตาดู enums ที่ยาวและมากมาย enums หรือที่เปลี่ยนบ่อย มิฉะนั้นนี่เป็นทางออกที่ดีสำหรับฉัน


10

หากคุณมาที่นี่เพื่อมองหาการใช้ "Enum" แบบง่าย ๆ แต่มีค่าเป็นสตริงแทนที่จะเป็น int นี่คือวิธีที่ง่ายที่สุด:

    public sealed class MetricValueList
    {
        public static readonly string Brand = "A4082457-D467-E111-98DC-0026B9010912";
        public static readonly string Name = "B5B5E167-D467-E111-98DC-0026B9010912";
    }

การดำเนินงาน:

var someStringVariable = MetricValueList.Brand;

2
มันอาจจะดีกว่าที่จะทำให้ตัวแปร consts static readonlyแทนการใช้
AndyGeek

1
const ไม่ดีสำหรับคลาสที่สาธารณะเข้าถึงได้เนื่องจากถูกอบในเวลาคอมไพล์คุณไม่สามารถแทนที่ DLL บุคคลที่สามโดยไม่ต้องคอมไพล์โค้ดทั้งหมดของคุณใหม่ด้วย consts.The ประสิทธิภาพการทำงานของ consts vs static อ่านได้เพียงเล็กน้อย
Kristian Williams

7

เมื่อฉันเผชิญหน้ากับปัญหานี้มีคำถามสองสามข้อที่ฉันพยายามค้นหาคำตอบก่อน:

  • ชื่อของค่า enum ของฉันเป็นมิตรเพียงพอสำหรับวัตถุประสงค์หรือฉันจำเป็นต้องให้ชื่อที่เป็นมิตรหรือไม่?
  • ฉันต้องไปกลับหรือไม่ นั่นคือฉันจะต้องนำค่าข้อความและแยกวิเคราะห์เป็นค่า enum หรือไม่
  • นี่เป็นสิ่งที่ฉันต้องทำเพื่อหลายคนในโครงการของฉันหรือแค่หนึ่งอัน?
  • ฉันจะนำเสนอองค์ประกอบ UI ประเภทใดโดยเฉพาะอย่างยิ่งฉันจะผูกพันกับ UI หรือใช้แผ่นคุณสมบัติ
  • จำเป็นต้องแปลเป็นภาษาท้องถิ่นหรือไม่?

วิธีที่ง่ายที่สุดในการทำเช่นนี้คือEnum.GetValue(และสนับสนุนการปัดเศษโดยใช้Enum.Parse) นอกจากนี้ยังเป็นเรื่องที่ควรค่าแก่การสร้างกTypeConverterตามที่ Steve Mitcham แนะนำเพื่อรองรับการเชื่อมโยง UI (ไม่จำเป็นต้องสร้างTypeConverterเมื่อคุณใช้แผ่นคุณสมบัติซึ่งเป็นหนึ่งในสิ่งที่ดีเกี่ยวกับแผ่นคุณสมบัติแม้ว่าลอร์ดรู้ว่าพวกเขามีปัญหาของตัวเอง)

โดยทั่วไปถ้าคำตอบของคำถามข้างต้นแสดงให้เห็นว่าของไม่ได้ไปทำงานขั้นตอนต่อไปของฉันคือการสร้างและเติมคงที่หรืออาจจะเป็นDictionary<MyEnum, string> Dictionary<Type, Dictionary<int, string>>ฉันมักจะข้ามขั้นตอนการตกแต่ง - the - code - with - คุณลักษณะขั้นกลางเพราะสิ่งที่มักจะมาลงหอกต่อไปคือความต้องการที่จะเปลี่ยนค่าเป็นมิตรหลังจากการปรับใช้ (บ่อยครั้ง แต่ไม่เสมอไปเพราะการแปล)


7

ฉันต้องการโพสต์สิ่งนี้เป็นความคิดเห็นในโพสต์ที่อ้างถึงด้านล่าง แต่ทำไม่ได้เพราะฉันมีตัวแทนไม่เพียงพอ - ดังนั้นโปรดอย่าลงคะแนน รหัสมีข้อผิดพลาดและฉันต้องการชี้ให้ผู้ใช้ที่พยายามใช้โซลูชันนี้:

[TypeConverter(typeof(CustomEnumTypeConverter(typeof(MyEnum))]
public enum MyEnum
{
  // The custom type converter will use the description attribute
  [Description("A custom description")]
  ValueWithCustomDescription,
  // This will be exposed exactly.
  Exact
}

ควรจะเป็น

[TypeConverter(typeof(CustomEnumTypeConverter<MyEnum>))]
public enum MyEnum
{
  // The custom type converter will use the description attribute
  [Description("A custom description")]
  ValueWithCustomDescription,

  // This will be exposed exactly.
  Exact
}

บรรเจิด!


5

ตัวแปรของฉัน

public struct Colors
{
    private String current;

    private static string red = "#ff0000";
    private static string green = "#00ff00";
    private static string blue = "#0000ff";

    private static IList<String> possibleColors; 

    public static Colors Red { get { return (Colors) red; } }
    public static Colors Green { get { return (Colors) green; } }
    public static Colors Blue { get { return (Colors) blue; } }

    static Colors()
    {
        possibleColors = new List<string>() {red, green, blue};
    }

    public static explicit operator String(Colors value)
    {
        return value.current;
    }

    public static explicit operator Colors(String value)
    {
        if (!possibleColors.Contains(value))
        {
            throw new InvalidCastException();
        }

        Colors color = new Colors();
        color.current = value;
        return color;
    }

    public static bool operator ==(Colors left, Colors right)
    {
        return left.current == right.current;
    }

    public static bool operator !=(Colors left, Colors right)
    {
        return left.current != right.current;
    }

    public bool Equals(Colors other)
    {
        return Equals(other.current, current);
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (obj.GetType() != typeof(Colors)) return false;
        return Equals((Colors)obj);
    }

    public override int GetHashCode()
    {
        return (current != null ? current.GetHashCode() : 0);
    }

    public override string ToString()
    {
        return current;
    }
}

โค้ดดูน่าเกลียดนิดหน่อย แต่การใช้งานโครงสร้างนี้เป็นการนำเสนอที่ค่อนข้างดี

Colors color1 = Colors.Red;
Console.WriteLine(color1); // #ff0000

Colors color2 = (Colors) "#00ff00";
Console.WriteLine(color2); // #00ff00

// Colors color3 = "#0000ff"; // Compilation error
// String color4 = Colors.Red; // Compilation error

Colors color5 = (Colors)"#ff0000";
Console.WriteLine(color1 == color5); // True

Colors color6 = (Colors)"#00ff00";
Console.WriteLine(color1 == color6); // False

นอกจากนี้ฉันคิดว่าถ้าจำเป็นต้องใช้ enums จำนวนมากการสร้างรหัส (เช่น T4) อาจถูกใช้


4

ตัวเลือกที่ 1:

public sealed class FormsAuth
{
     public override string ToString{return "Forms Authtentication";}
}
public sealed class WindowsAuth
{
     public override string ToString{return "Windows Authtentication";}
}

public sealed class SsoAuth
{
     public override string ToString{return "SSO";}
}

แล้ว

object auth = new SsoAuth(); //or whatever

//...
//...
// blablabla

DoSomethingWithTheAuth(auth.ToString());

ตัวเลือก 2:

public enum AuthenticationMethod
{
        FORMS = 1,
        WINDOWSAUTHENTICATION = 2,
        SINGLESIGNON = 3
}

public class MyClass
{
    private Dictionary<AuthenticationMethod, String> map = new Dictionary<AuthenticationMethod, String>();
    public MyClass()
    {
         map.Add(AuthenticationMethod.FORMS,"Forms Authentication");
         map.Add(AuthenticationMethod.WINDOWSAUTHENTICATION ,"Windows Authentication");
         map.Add(AuthenticationMethod.SINGLESIGNON ,"SSo Authentication");
    }
}

4

หากคุณคิดถึงปัญหาที่เราพยายามแก้ไขนั่นไม่ใช่ปัญหาที่เราต้องการ เราต้องการวัตถุที่อนุญาตให้มีค่าจำนวนหนึ่งที่เกี่ยวข้องกับ eachother; กล่าวอีกนัยหนึ่งเพื่อกำหนดชั้นเรียน

รูปแบบ Enum แบบปลอดภัยของ Jakub Šturcเป็นตัวเลือกที่ดีที่สุดที่ฉันเห็นที่นี่

ดูที่มัน

  • มันมีตัวสร้างส่วนตัวดังนั้นเฉพาะชั้นเรียนเท่านั้นที่สามารถกำหนดค่าที่อนุญาต
  • มันเป็นคลาสที่ปิดผนึกเพื่อให้ค่าไม่สามารถแก้ไขได้ผ่านการสืบทอด
  • มันเป็นประเภทที่ปลอดภัยช่วยให้วิธีการของคุณจะต้องมีเพียงประเภทนั้น
  • ไม่มีประสิทธิภาพการสะท้อนที่เกิดขึ้นจากการเข้าถึงค่าต่างๆ
  • และสุดท้ายสามารถแก้ไขเพื่อเชื่อมโยงมากกว่าสองฟิลด์เข้าด้วยกันตัวอย่างเช่นชื่อคำอธิบายและค่าตัวเลข

4

สำหรับฉันวิธีการปฏิบัติเป็นชั้นในชั้นเรียนตัวอย่าง:

public class MSEModel
{
    class WITS
    {
        public const string DATE = "5005";
        public const string TIME = "5006";
        public const string MD = "5008";
        public const string ROP = "5075";
        public const string WOB = "5073";
        public const string RPM = "7001";
... 
    }

4

ฉันสร้างคลาสพื้นฐานสำหรับการสร้าง enums แบบสตริงใน. NET มันเป็นเพียงหนึ่งใน C # ไฟล์ที่คุณสามารถคัดลอกและวางลงในโครงการของคุณหรือติดตั้งผ่านทาง NuGet แพคเกจชื่อStringEnum GitHub Repo

  • Intellisense จะแนะนำชื่อ enum หากคลาสมีการเพิ่มความคิดเห็น<completitionlist>ด้วยความคิดเห็น xml (ทำงานได้ทั้ง C # และ VB)

การสาธิต Intellisense

  • การใช้งานคล้ายกับ Enum ปกติ:
///<completionlist cref="HexColor"/> 
class HexColor : StringEnum<HexColor>
{
    public static readonly HexColor Blue = Create("#FF0000");
    public static readonly HexColor Green = Create("#00FF00");
    public static readonly HexColor Red = Create("#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)

instalation:

  • วางคลาสฐานของ StringEnum ต่อไปนี้ลงในโครงการของคุณ ( เวอร์ชั่นล่าสุด )
  • หรือติดตั้งStringEnumแพคเกจ NuGet ซึ่งอยู่บนพื้นฐาน.Net Standard 1.0จึงทำงานบน.Net Core> = 1.0 .Net Framework> = 4.5 Mono> = 4.6 ฯลฯ
    /// <summary>
    /// Base class for creating string-valued enums in .NET.<br/>
    /// Provides static Parse() and TryParse() methods and implicit cast to string.
    /// </summary>
    /// <example> 
    /// <code>
    /// class Color : StringEnum &lt;Color&gt;
    /// {
    ///     public static readonly Color Blue = Create("Blue");
    ///     public static readonly Color Red = Create("Red");
    ///     public static readonly Color Green = Create("Green");
    /// }
    /// </code>
    /// </example>
    /// <typeparam name="T">The string-valued enum type. (i.e. class Color : StringEnum&lt;Color&gt;)</typeparam>
    public abstract class StringEnum<T> : IEquatable<T> where T : StringEnum<T>, new()
    {
        protected string Value;
        private static Dictionary<string, T> valueDict = new Dictionary<string, T>();
        protected static T Create(string value)
        {
            if (value == null)
                return null; // the null-valued instance is null.

            var result = new T() { Value = value };
            valueDict.Add(value, 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 and takes O(log n). False allows different case but is little bit slower (O(n))</param>
        public static T Parse(string value, bool caseSensitive = true)
        {
            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. False allows different case but is slower: O(n)</param>
        public static T TryParse(string value, bool caseSensitive = true)
        {
            if (value == null) return null;
            if (valueDict.Count == 0) System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle); // force static fields initialization
            if (caseSensitive)
            {
                if (valueDict.TryGetValue(value, out T item))
                    return item;
                else
                    return null;
            }
            else
            {
                // slower O(n) case insensitive search
                return valueDict.FirstOrDefault(f => f.Key.Equals(value, StringComparison.OrdinalIgnoreCase)).Value;
                // Why Ordinal? => https://esmithy.net/2007/10/15/why-stringcomparisonordinal-is-usually-the-right-choice/
            }
        }
    }

3

นี่เป็นอีกวิธีในการทำงานของการเชื่อมโยงสตริงกับ enums:

struct DATABASE {
    public enum enums {NOTCONNECTED, CONNECTED, ERROR}
    static List<string> strings =
        new List<string>() {"Not Connected", "Connected", "Error"};

    public string GetString(DATABASE.enums value) {
        return strings[(int)value];
    }
}

วิธีการนี้เรียกว่าดังนี้:

public FormMain() {
    DATABASE dbEnum;

    string enumName = dbEnum.GetString(DATABASE.enums.NOTCONNECTED);
}

คุณสามารถจัดกลุ่ม enums ที่เกี่ยวข้องในโครงสร้างของตัวเอง เนื่องจากวิธีนี้ใช้ชนิด enum คุณสามารถใช้ Intellisense เพื่อแสดงรายการของ enums เมื่อทำการGetString()โทร

คุณสามารถเลือกใช้โอเปอเรเตอร์ใหม่ในโครงสร้างDATABASEได้ ไม่ใช้หมายความว่าListจะไม่มีการจัดสรรสตริงจนกว่าจะมีการGetString()โทรครั้งแรก


3

คำตอบที่ดีมากมายที่นี่ แต่ในกรณีของฉันไม่ได้แก้สิ่งที่ฉันต้องการจาก "string enum" ซึ่งก็คือ:

  1. ใช้งานได้ในคำสั่ง switch เช่น switch (myEnum)
  2. สามารถใช้ในพารามิเตอร์ฟังก์ชันเช่น foo (myEnum type)
  3. สามารถอ้างอิงได้เช่น myEnum.FirstElement
  4. ฉันสามารถใช้สตริงเช่น foo ("FirstElement") == foo (myEnum.FirstElement)

1,2 และ 4 สามารถแก้ไขได้จริงด้วย C # Typedef ของสตริง (เนื่องจากสตริงสามารถสลับได้ใน c #)

3 สามารถแก้ไขได้โดยสตริงคงที่ ดังนั้นหากคุณมีความต้องการแบบเดียวกันนี่เป็นวิธีที่ง่ายที่สุด:

public sealed class Types
{

    private readonly String name;

    private Types(String name)
    {
        this.name = name;

    }

    public override String ToString()
    {
        return name;
    }

    public static implicit operator Types(string str)
    {
        return new Types(str);

    }
    public static implicit operator string(Types str)
    {
        return str.ToString();
    }


    #region enum

    public const string DataType = "Data";
    public const string ImageType = "Image";
    public const string Folder = "Folder";
    #endregion

}

สิ่งนี้อนุญาตให้:

    public TypeArgs(Types SelectedType)
    {
        Types SelectedType = SelectedType
    }

และ

public TypeObject CreateType(Types type)
    {
        switch (type)
        {

            case Types.ImageType:
              //
                break;

            case Types.DataType:
             //
                break;

        }
    }

โดยที่ CreateType สามารถเรียกใช้ด้วยสตริงหรือชนิด อย่างไรก็ตามข้อเสียคือสตริงใด ๆ จะเป็น enum ที่ถูกต้องโดยอัตโนมัตินี้สามารถแก้ไขได้ แต่แล้วมันจะต้องมีฟังก์ชั่น init บางชนิด ...

ตอนนี้ถ้าค่า int เป็นสิ่งสำคัญสำหรับคุณ (อาจใช้เพื่อเปรียบเทียบความเร็ว) คุณสามารถใช้แนวคิดบางอย่างจาก Jakub Šturcคำตอบที่ยอดเยี่ยมและทำบางสิ่งที่บ้าไปหน่อยนี่คือการแทงของฉันที่มัน:

    public sealed class Types
{
    private static readonly Dictionary<string, Types> strInstance = new Dictionary<string, Types>();
    private static readonly Dictionary<int, Types> intInstance = new Dictionary<int, Types>();

    private readonly String name;
    private static int layerTypeCount = 0;
    private int value;
    private Types(String name)
    {
        this.name = name;
        value = layerTypeCount++;
        strInstance[name] = this;
        intInstance[value] = this;
    }

    public override String ToString()
    {
        return name;
    }


    public static implicit operator Types(int val)
    {
        Types result;
        if (intInstance.TryGetValue(val, out result))
            return result;
        else
            throw new InvalidCastException();
    }

    public static implicit operator Types(string str)
    {
        Types result;
        if (strInstance.TryGetValue(str, out result))
        {
            return result;
        }
        else
        {
            result = new Types(str);
            return result;
        }

    }
    public static implicit operator string(Types str)
    {
        return str.ToString();
    }

    public static bool operator ==(Types a, Types b)
    {
        return a.value == b.value;
    }
    public static bool operator !=(Types a, Types b)
    {
        return a.value != b.value;
    }

    #region enum

    public const string DataType = "Data";
    public const string ImageType = "Image";

    #endregion

}

แต่แน่นอน "Types bob = 4;" จะไม่มีความหมายหากคุณไม่ได้กำหนดค่าเริ่มต้นก่อนซึ่งจะเอาชนะจุด ...

แต่ในทางทฤษฎี TypeA == TypeB จะเร็วกว่า ...


3

ถ้าฉันเข้าใจคุณอย่างถูกต้องคุณสามารถใช้. ToString () เพื่อดึงชื่อของ enum จากค่า (สมมติว่ามันถูกใช้เป็น Enum); หากคุณมีช่องว่างเปล่า (ให้พูดจากฐานข้อมูลหรือบางสิ่ง) คุณสามารถส่งไปยัง enum ได้ก่อน ทั้งสองวิธีด้านล่างจะให้ชื่อ enum แก่คุณ

AuthenticationMethod myCurrentSetting = AuthenticationMethod.FORMS;
Console.WriteLine(myCurrentSetting); // Prints: FORMS
string name = Enum.GetNames(typeof(AuthenticationMethod))[(int)myCurrentSetting-1];
Console.WriteLine(name); // Prints: FORMS

โปรดจำไว้ว่าเทคนิคที่สองถือว่าคุณใช้ ints และดัชนีของคุณคือ 1 (ไม่ใช่ 0 ตาม) ฟังก์ชั่น GetNames นั้นค่อนข้างหนักโดยการเปรียบเทียบคุณกำลังสร้างอาเรย์ทั้งหมดในแต่ละครั้งที่ถูกเรียก อย่างที่คุณเห็นในเทคนิคแรก. ToString () เรียกว่าโดยปริยาย ทั้งสองสิ่งนี้ถูกกล่าวถึงแล้วในคำตอบของหลักสูตรฉันแค่พยายามอธิบายความแตกต่างระหว่างพวกเขา


3

โพสต์เก่า แต่ ...

คำตอบนี้อาจง่ายมาก ใช้Enum.ToString ()ฟังก์ชั่น

ฟังก์ชั่นนี้มี 6 โอเวอร์โหลดคุณสามารถใช้ Enum.Tostring ("F") หรือ Enum.ToString () เพื่อส่งกลับค่าสตริง ไม่จำเป็นต้องไปยุ่งกับสิ่งอื่นใด นี่คือตัวอย่างการทำงาน

โปรดทราบว่าวิธีนี้อาจใช้ไม่ได้กับคอมไพเลอร์ทั้งหมด ( ตัวอย่างนี้ใช้ไม่ได้ตามที่คาดหวัง ) แต่อย่างน้อยก็ใช้ได้กับคอมไพเลอร์ตัวล่าสุด


2

ตาม MSDN: http://msdn.microsoft.com/en-us/library/cc138362.aspx

foreach (string str in Enum.GetNames(typeof(enumHeaderField)))
{
    Debug.WriteLine(str);
}

str จะเป็นชื่อของฟิลด์


2
นี้จะให้ชื่อของ enum คุณยังสามารถใช้ ToString () สำหรับสิ่งนี้ไม่ใช่สิ่งที่ถูกถาม ชำระเงินmsdn.microsoft.com/en-us/library/system.enum.getname.aspxสำหรับข้อมูลเพิ่มเติมเกี่ยวกับ bubu ของคุณ
Mickey Perlstein

2

หลังจากอ่านทั้งหมดข้างต้นฉันรู้สึกว่าพวกเขามีความซับซ้อนเกินกว่าปัญหาของการเปลี่ยนผู้แจงนับเป็นสตริง ฉันชอบความคิดของการมีคุณลักษณะมากกว่าเขตข้อมูลที่ระบุ แต่ฉันคิดว่าคุณลักษณะส่วนใหญ่จะใช้สำหรับ Meta-data แต่ในกรณีของคุณฉันคิดว่าสิ่งที่คุณต้องมีคือการโลคัลไลเซชัน

public enum Color 
{ Red = 1, Green = 2, Blue = 3}


public static EnumUtils 
{
   public static string GetEnumResourceString(object enumValue)
    {
        Type enumType = enumValue.GetType();
        string value = Enum.GetName(enumValue.GetType(), enumValue);
        string resourceKey = String.Format("{0}_{1}", enumType.Name, value);
        string result = Resources.Enums.ResourceManager.GetString(resourceKey);
        if (string.IsNullOrEmpty(result))
        {
            result = String.Format("{0}", value);
        }
        return result;
    }
}

ตอนนี้ถ้าเราพยายามเรียกวิธีข้างต้นเราสามารถเรียกวิธีนี้

public void Foo()
{
  var col = Color.Red;
  Console.WriteLine (EnumUtils.GetEnumResourceString (col));
}

สิ่งที่คุณต้องทำก็แค่สร้างไฟล์ทรัพยากรที่มีค่าตัวแจงนับทั้งหมดและสตริงที่เกี่ยวข้อง

ชื่อทรัพยากรมูลค่าทรัพยากร
Color_Red My String Color เป็นสีแดง
Color_Blue Blueeey
Color_Green Hulk Color

จริงๆแล้วสิ่งที่ดีมากเกี่ยวกับเรื่องนี้ก็คือมันจะมีประโยชน์มากหากคุณต้องการใบสมัครของคุณเป็นภาษาท้องถิ่นเนื่องจากสิ่งที่คุณต้องทำคือเพียงแค่สร้างไฟล์ทรัพยากรใหม่ด้วยภาษาใหม่ของคุณ! และ Voe-la!


1

เมื่อฉันอยู่ในสถานการณ์อย่างที่ฉันเสนอวิธีการแก้ปัญหาด้านล่าง

และในฐานะชั้นเรียนการบริโภคที่คุณมี

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyApp.Dictionaries
{
    class Greek
    {

        public static readonly string Alpha = "Alpha";
        public static readonly string Beta = "Beta";
        public static readonly string Gamma = "Gamma";
        public static readonly string Delta = "Delta";


        private static readonly BiDictionary<int, string> Dictionary = new BiDictionary<int, string>();


        static Greek() {
            Dictionary.Add(1, Alpha);
            Dictionary.Add(2, Beta);
            Dictionary.Add(3, Gamma);
            Dictionary.Add(4, Delta);
        }

        public static string getById(int id){
            return Dictionary.GetByFirst(id);
        }

        public static int getByValue(string value)
        {
            return Dictionary.GetBySecond(value);
        }

    }
}

และการใช้พจนานุกรมสองทิศทาง: อิงจากนี้ ( https://stackoverflow.com/a/255638/986160 ) สมมติว่าคีย์จะเชื่อมโยงกับค่าเดียวในพจนานุกรมและคล้ายกับ ( https://stackoverflow.com/a / 255630/986160 ) แต่ดูสง่างามกว่าเล็กน้อย พจนานุกรมนี้สามารถนับได้และคุณสามารถกลับไปกลับมาจาก ints ไปยังสตริง นอกจากนี้คุณไม่จำเป็นต้องมีสตริงใด ๆ ใน codebase ของคุณยกเว้นคลาสนี้

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace MyApp.Dictionaries
{

    class BiDictionary<TFirst, TSecond> : IEnumerable
    {
        IDictionary<TFirst, TSecond> firstToSecond = new Dictionary<TFirst, TSecond>();
        IDictionary<TSecond, TFirst> secondToFirst = new Dictionary<TSecond, TFirst>();

        public void Add(TFirst first, TSecond second)
        {
            firstToSecond.Add(first, second);
            secondToFirst.Add(second, first);
        }

        public TSecond this[TFirst first]
        {
            get { return GetByFirst(first); }
        }

        public TFirst this[TSecond second]
        {
            get { return GetBySecond(second); }
        }

        public TSecond GetByFirst(TFirst first)
        {
            return firstToSecond[first];
        }

        public TFirst GetBySecond(TSecond second)
        {
            return secondToFirst[second];
        }

        public IEnumerator GetEnumerator()
        {
            return GetFirstEnumerator();
        }

        public IEnumerator GetFirstEnumerator()
        {
            return firstToSecond.GetEnumerator();
        }

        public IEnumerator GetSecondEnumerator()
        {
            return secondToFirst.GetEnumerator();
        }
    }
}

1

สำหรับชุด enum สตริงขนาดใหญ่ตัวอย่างที่แสดงสามารถกลายเป็นน่าเบื่อได้ หากคุณต้องการรายการของรหัสสถานะหรือรายการของ enums ตามสตริงอื่น ๆ ระบบแอ็ตทริบิวต์น่ารำคาญที่จะใช้และคลาสแบบสแตติกที่มีอินสแตนซ์ของตัวเองน่ารำคาญในการกำหนดค่า สำหรับวิธีการแก้ปัญหาของฉันฉันใช้ T4 templating เพื่อให้ง่ายขึ้นที่จะมี enum ที่สนับสนุนสตริง ผลลัพธ์จะออกมาคล้ายกับการทำงานของคลาส HttpMethod

คุณสามารถใช้สิ่งนี้:

    string statusCode = ResponseStatusCode.SUCCESS; // Automatically converts to string when needed
    ResponseStatusCode codeByValueOf = ResponseStatusCode.ValueOf(statusCode); // Returns null if not found

    // Implements TypeConverter so you can use it with string conversion methods.
    var converter = System.ComponentModel.TypeDescriptor.GetConverter(typeof(ResponseStatusCode));
    ResponseStatusCode code = (ResponseStatusCode) converter.ConvertFromInvariantString(statusCode);

    // You can get a full list of the values
    bool canIterateOverValues = ResponseStatusCode.Values.Any(); 

    // Comparisons are by value of the "Name" property. Not by memory pointer location.
    bool implementsByValueEqualsEqualsOperator = "SUCCESS" == ResponseStatusCode.SUCCESS; 

คุณเริ่มต้นด้วยไฟล์ Enum.tt

<#@ include file="StringEnum.ttinclude" #>


<#+
public static class Configuration
{
    public static readonly string Namespace = "YourName.Space";
    public static readonly string EnumName = "ResponseStatusCode";
    public static readonly bool IncludeComments = true;

    public static readonly object Nodes = new
    {
        SUCCESS = "The response was successful.",
        NON_SUCCESS = "The request was not successful.",
        RESOURCE_IS_DISCONTINUED = "The resource requested has been discontinued and can no longer be accessed."
    };
}
#>

จากนั้นคุณเพิ่มไฟล์ StringEnum.ttinclude ของคุณ

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#@ CleanupBehavior processor="T4VSHost" CleanupAfterProcessingtemplate="true" #>

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;

namespace <#= Configuration.Namespace #>
{
    /// <summary>
    /// TypeConverter implementations allow you to use features like string.ToNullable(T).
    /// </summary>
    public class <#= Configuration.EnumName #>TypeConverter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
        }

        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            var casted = value as string;

            if (casted != null)
            {
                var result = <#= Configuration.EnumName #>.ValueOf(casted);
                if (result != null)
                {
                    return result;
                }
            }

            return base.ConvertFrom(context, culture, value);
        }

        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            var casted = value as <#= Configuration.EnumName #>;
            if (casted != null && destinationType == typeof(string))
            {
                return casted.ToString();
            }

            return base.ConvertTo(context, culture, value, destinationType);
        }
    }

    [TypeConverter(typeof(<#= Configuration.EnumName #>TypeConverter))]
    public class <#= Configuration.EnumName #> : IEquatable<<#= Configuration.EnumName #>>
    {
//---------------------------------------------------------------------------------------------------
// V A L U E S _ L I S T
//---------------------------------------------------------------------------------------------------
<# Write(Helpers.PrintEnumProperties(Configuration.Nodes)); #>

        private static List<<#= Configuration.EnumName #>> _list { get; set; } = null;
        public static List<<#= Configuration.EnumName #>> ToList()
        {
            if (_list == null)
            {
                _list = typeof(<#= Configuration.EnumName #>).GetFields().Where(x => x.IsStatic && x.IsPublic && x.FieldType == typeof(<#= Configuration.EnumName #>))
                    .Select(x => x.GetValue(null)).OfType<<#= Configuration.EnumName #>>().ToList();
            }

            return _list;
        }

        public static List<<#= Configuration.EnumName #>> Values()
        {
            return ToList();
        }

        /// <summary>
        /// Returns the enum value based on the matching Name of the enum. Case-insensitive search.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static <#= Configuration.EnumName #> ValueOf(string key)
        {
            return ToList().FirstOrDefault(x => string.Compare(x.Name, key, true) == 0);
        }


//---------------------------------------------------------------------------------------------------
// I N S T A N C E _ D E F I N I T I O N
//---------------------------------------------------------------------------------------------------      
        public string Name { get; private set; }
        public string Description { get; private set; }
        public override string ToString() { return this.Name; }

        /// <summary>
        /// Implcitly converts to string.
        /// </summary>
        /// <param name="d"></param>
        public static implicit operator string(<#= Configuration.EnumName #> d)
        {
            return d.ToString();
        }

        /// <summary>
        /// Compares based on the == method. Handles nulls gracefully.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator !=(<#= Configuration.EnumName #> a, <#= Configuration.EnumName #> b)
        {
            return !(a == b);
        }

        /// <summary>
        /// Compares based on the .Equals method. Handles nulls gracefully.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator ==(<#= Configuration.EnumName #> a, <#= Configuration.EnumName #> b)
        {
            return a?.ToString() == b?.ToString();
        }

        /// <summary>
        /// Compares based on the .ToString() method
        /// </summary>
        /// <param name="o"></param>
        /// <returns></returns>
        public override bool Equals(object o)
        {
            return this.ToString() == o?.ToString();
        }

        /// <summary>
        /// Compares based on the .ToString() method
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public bool Equals(<#= Configuration.EnumName #> other)
        {
            return this.ToString() == other?.ToString();
        }

        /// <summary>
        /// Compares based on the .Name property
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return this.Name.GetHashCode();
        }
    }
}

<#+

public static class Helpers
{
        public static string PrintEnumProperties(object nodes)
        {
            string o = "";
            Type nodesTp = Configuration.Nodes.GetType();
            PropertyInfo[] props = nodesTp.GetProperties().OrderBy(p => p.Name).ToArray();

            for(int i = 0; i < props.Length; i++)
            {
                var prop = props[i];
                if (Configuration.IncludeComments)
                {
                    o += "\r\n\r\n";
                    o += "\r\n        ///<summary>";
                    o += "\r\n        /// "+Helpers.PrintPropertyValue(prop, Configuration.Nodes);
                    o += "\r\n        ///</summary>";
                }

                o += "\r\n        public static readonly "+Configuration.EnumName+" "+prop.Name+ " = new "+Configuration.EnumName+"(){ Name = \""+prop.Name+"\", Description = "+Helpers.PrintPropertyValue(prop, Configuration.Nodes)+ "};";
            }

            o += "\r\n\r\n";

            return o;
        }

        private static Dictionary<string, string> GetValuesMap()
        {
            Type nodesTp = Configuration.Nodes.GetType();
            PropertyInfo[] props= nodesTp.GetProperties();
            var dic = new Dictionary<string,string>();
            for(int i = 0; i < props.Length; i++)
            {
                var prop = nodesTp.GetProperties()[i];
                dic[prop.Name] = prop.GetValue(Configuration.Nodes).ToString();
            }
            return dic;
        }

        public static string PrintMasterValuesMap(object nodes)
        {
            Type nodesTp = Configuration.Nodes.GetType();
            PropertyInfo[] props= nodesTp.GetProperties();
            string o = "        private static readonly Dictionary<string, string> ValuesMap = new Dictionary<string, string>()\r\n        {";
            for(int i = 0; i < props.Length; i++)
            {
                var prop = nodesTp.GetProperties()[i];
                o += "\r\n            { \""+prop.Name+"\", "+(Helpers.PrintPropertyValue(prop,Configuration.Nodes)+" },");
            }
            o += ("\r\n        };\r\n");

            return o;
        }


        public static string PrintPropertyValue(PropertyInfo prop, object objInstance)
        {
            switch(prop.PropertyType.ToString()){
                case "System.Double":
                    return prop.GetValue(objInstance).ToString()+"D";
                case "System.Float":
                    return prop.GetValue(objInstance).ToString()+"F";
                case "System.Decimal":
                    return prop.GetValue(objInstance).ToString()+"M";
                case "System.Long":
                    return prop.GetValue(objInstance).ToString()+"L";
                case "System.Boolean":
                case "System.Int16":
                case "System.Int32":
                    return prop.GetValue(objInstance).ToString().ToLowerInvariant();
                case "System.String":
                    return "\""+prop.GetValue(objInstance)+"\"";
            }

            return prop.GetValue(objInstance).ToString();
        }

        public static string _ (int numSpaces)
        {
            string o = "";
            for(int i = 0; i < numSpaces; i++){
                o += " ";
            }

            return o;
        }
}
#>

สุดท้ายคุณก็ทำการคอมไพล์ไฟล์ Enum.tt ของคุณใหม่และผลลัพธ์จะเป็นดังนี้

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System;
using System.Linq;
using System.Collections.Generic;

namespace YourName.Space
{
    public class ResponseStatusCode
    {
//---------------------------------------------------------------------------------------------------
// V A L U E S _ L I S T 
//---------------------------------------------------------------------------------------------------



        ///<summary>
        /// "The response was successful."
        ///</summary>
        public static readonly ResponseStatusCode SUCCESS = new ResponseStatusCode(){ Name = "SUCCESS", Description = "The response was successful."};


        ///<summary>
        /// "The request was not successful."
        ///</summary>
        public static readonly ResponseStatusCode NON_SUCCESS = new ResponseStatusCode(){ Name = "NON_SUCCESS", Description = "The request was not successful."};


        ///<summary>
        /// "The resource requested has been discontinued and can no longer be accessed."
        ///</summary>
        public static readonly ResponseStatusCode RESOURCE_IS_DISCONTINUED = new ResponseStatusCode(){ Name = "RESOURCE_IS_DISCONTINUED", Description = "The resource requested has been discontinued and can no longer be accessed."};


        private static List<ResponseStatusCode> _list { get; set; } = null;
        public static List<ResponseStatusCode> ToList()
        {
            if (_list == null)
            {
                _list = typeof(ResponseStatusCode).GetFields().Where(x => x.IsStatic && x.IsPublic && x.FieldType == typeof(ResponseStatusCode))
                    .Select(x => x.GetValue(null)).OfType<ResponseStatusCode>().ToList();
            }

            return _list;
        }

        public static List<ResponseStatusCode> Values()
        {
            return ToList();
        }

        /// <summary>
        /// Returns the enum value based on the matching Name of the enum. Case-insensitive search.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static ResponseStatusCode ValueOf(string key)
        {
            return ToList().FirstOrDefault(x => string.Compare(x.Name, key, true) == 0);
        }


//---------------------------------------------------------------------------------------------------
// I N S T A N C E _ D E F I N I T I O N 
//---------------------------------------------------------------------------------------------------       
        public string Name { get; set; }
        public string Description { get; set; }
        public override string ToString() { return this.Name; }

        /// <summary>
        /// Implcitly converts to string.
        /// </summary>
        /// <param name="d"></param>
        public static implicit operator string(ResponseStatusCode d)
        {
            return d.ToString();
        }

        /// <summary>
        /// Compares based on the == method. Handles nulls gracefully.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator !=(ResponseStatusCode a, ResponseStatusCode b)
        {
            return !(a == b);
        }

        /// <summary>
        /// Compares based on the .Equals method. Handles nulls gracefully.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator ==(ResponseStatusCode a, ResponseStatusCode b)
        {
            return a?.ToString() == b?.ToString();
        }

        /// <summary>
        /// Compares based on the .ToString() method
        /// </summary>
        /// <param name="o"></param>
        /// <returns></returns>
        public override bool Equals(object o)
        {
            return this.ToString() == o?.ToString();
        }

        /// <summary>
        /// Compares based on the .Name property
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return this.Name.GetHashCode();
        }
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.