หลักการตั้งชื่อ C # สำหรับ enum และคุณสมบัติที่ตรงกัน


93

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

public class Car
{
  public enum Status
  {
    Off,
    Starting,
    Moving
  };

  Status status = Status.Off;

  public Status Status // <===== Won't compile =====
  {
    get { return status; }
    set { status = value; DoSomething(); }
  }
}

ถ้าสถานะ enum เป็นประเภทต่างๆฉันจะวางไว้นอกชั้นเรียนและปัญหาจะได้รับการแก้ไข แต่สถานะใช้กับรถยนต์เท่านั้นดังนั้นจึงไม่สมเหตุสมผลที่จะประกาศ enum นอกชั้นเรียน

คุณใช้หลักการตั้งชื่ออะไรในกรณีนี้?

หมายเหตุ: คำถามนี้มีการถกเถียงกันบางส่วนในความคิดเห็นของคำตอบของคำถามนี้ เนื่องจากมันไม่ใช่หลักคำถามจึงไม่ได้รับการเปิดเผยมากนัก

แก้ไข: Filip Ekberg แนะนำวิธีแก้ปัญหาที่ยอดเยี่ยมของ IMO สำหรับกรณีเฉพาะของ 'สถานะ' แต่ฉันจะน่าสนใจที่จะอ่านเกี่ยวกับการแก้ปัญหาที่ชื่อของ enum / คุณสมบัติที่แตกต่างกันในขณะที่ไมเคิล Prewecki ของคำตอบ

แก้ไข 2 (พ.ค. แต่ฉันมาชอบมากขึ้นเรื่อย ๆ ตอนนี้ฉันใช้มันสำหรับ enums ปกติเช่นกัน


1
ฉันไม่คิดว่าจะมีวิธีแก้ปัญหาที่ดีมากมายสำหรับสิ่งนี้หากคุณต้องการให้ enum ซ้อนอยู่ในชั้นเรียนของคุณ จริงๆแล้วฉันชอบที่จะแยก enum แล้วมันก็ไม่ได้ทำให้เกิดปัญหา แต่ฉันเห็นประเด็นของคุณในเชิงปรัชญาเกี่ยวกับการต้องการรังมัน
Craig Shearer

คำตอบ:


32

ฉันจะเพิ่มเงิน 1 ยูโรในการสนทนา แต่อาจไม่ได้เพิ่มอะไรใหม่

ทางออกที่ชัดเจนคือการย้ายสถานะออกจากการเป็น Enum ที่ซ้อนกัน NET ส่วนใหญ่ (ยกเว้นบางตัวใน Windows.Forms namespace) ไม่ซ้อนกันและทำให้การใช้งานสำหรับนักพัฒนาที่ใช้ API ของคุณน่ารำคาญโดยต้องนำหน้าชื่อคลาส

สิ่งหนึ่งที่ยังไม่ได้กล่าวถึงคือ flag enums ตามแนวทาง MSDN ควรเป็นคำนามที่เป็นพหูพจน์ซึ่งคุณอาจรู้อยู่แล้ว (Status เป็น enum ธรรมดาดังนั้นควรใช้คำนามเอกพจน์)

รัฐ (enum เรียกว่า States) เป็นคำเรียก "สถานะ" เป็นคำนามของคำนามที่ภาษาอังกฤษเหมือนกับภาษาส่วนใหญ่ของเราดูดซึมมาจากภาษาละติน Vocative คือสิ่งที่คุณตั้งชื่อคำนามสำหรับเงื่อนไขและคำนามเป็นเรื่องของคำกริยา

กล่าวอีกนัยหนึ่งเมื่อรถเคลื่อนที่นั่นคือคำกริยา - การเคลื่อนที่คือสถานะของมัน แต่รถไม่ดับเครื่องยนต์ทำ หรือไม่สตาร์ทเครื่องยนต์ก็ไม่ทำ (คุณอาจเลือกตัวอย่างที่นี่ซึ่งอาจไม่เกี่ยวข้อง)

public class Car
{
  VehicleState _vehicleState= VehicleState.Stationary;

  public VehicleState VehicleState 
  {
    get { return _vehicleState; }
    set { _vehicleState = value; DoSomething(); }
  }
}

public enum VehicleState
{
    Stationary, Idle, Moving
}

รัฐเป็นคำนามทั่วไปมันจะดีกว่าไหมที่จะอธิบายว่ารัฐหมายถึงอะไร? เหมือนที่ฉันทำข้างต้น

ตัวอย่างประเภทในมุมมองของฉันไม่ได้อ้างถึงประเภทผู้อ่าน แต่เป็นฐานข้อมูล ฉันจะชอบมากกว่านี้ถ้าคุณกำลังอธิบายผลิตภัณฑ์ฐานข้อมูลของผู้อ่านซึ่งไม่จำเป็นต้องเกี่ยวข้องกับประเภทของผู้อ่าน (เช่นประเภทของผู้อ่านอาจเป็นไปข้างหน้าเท่านั้นแคชและอื่น ๆ ) ดังนั้น

reader.Database = Databases.Oracle;

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


24
ความเข้าใจของฉันคือแฟล็กควรเป็นพหูพจน์ไม่ใช่ enums ธรรมดา
Serge Wautier

8
เกี่ยวกับการย้าย enums ออกจากชั้นเรียนฉันยังไม่เข้าใจว่าทำไม CarState ถึงสะดวกกว่า Car.State อย่างไรก็ตามฉันไม่เข้าใจด้านบวกของการเอา enum ออกจากคลาสเมื่อ enum นี้อธิบายถึงพฤติกรรมของคลาสนี้เท่านั้น
Serge Wautier

ฉันควรเขียนนามวลีเช่น FileOptions ไม่ใช่แค่คำนามฉันได้อัปเดตคำตอบแล้ว ฉันคิดว่าชื่อคลาส Enum เป็นเพียงการตั้งค่า - ฉันไม่พบตัวอย่างใด ๆ ในกรอบงานที่ฉันคัดลอกมา
Chris S

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

1
ฉันรู้ว่าฉันมาช้าไป 1 1/2 ปีที่นี่ แต่public class EngineStateควรอยู่public enum EngineStateในตัวอย่างใช่ไหม
David Murdoch

36

คำจำกัดความของ "ปิด" "เริ่มต้น" และ "ย้าย" คือสิ่งที่ฉันเรียกว่า "สถานะ" และเมื่อคุณบอกเป็นนัยว่าคุณกำลังใช้ "สถานะ" นั่นคือ "สถานะ" ของคุณ ดังนั้น!

public class Car
{
  public enum State
  {
    Off,
    Starting,
    Moving
  };

  State state = State.Off;

  public State Status
  {
    get { return state ; }
    set { state= value; DoSomething(); }
  }
}

หากเรานำตัวอย่างอื่นจากตัวอย่างที่ระบุไว้ในที่ที่คุณต้องการใช้คำว่า "Type" ในกรณีนี้:

public class DataReader
{
    public enum Type
    {
        Sql,
        Oracle,
        OleDb
    }

    public Type Type { get; set; } // <===== Won't compile =====

}

คุณต้องดูว่า enums และ enums มีความแตกต่างกันจริงไหม? แต่เมื่อสร้างเฟรมเวิร์กหรือพูดถึงสถาปัตยกรรมคุณต้องให้ความสำคัญกับความคล้ายคลึงกันให้ค้นหา:

เมื่อบางสิ่งถูกตั้งค่าเป็นสถานะจะกำหนดเป็นสถานะ "สิ่งต่างๆ"

ตัวอย่าง: สถานะของรถอยู่ในสถานะกำลังทำงานสถานะที่ถูกหยุดและอื่น ๆ

สิ่งที่คุณต้องการบรรลุในตัวอย่างที่สองมีดังนี้:

myDataReader.Type = DataReader.Database.OleDb

คุณอาจคิดว่าสิ่งนี้ขัดต่อสิ่งที่ฉันเคยสั่งสอนกับคนอื่น ๆ ว่าคุณต้องทำตามมาตรฐาน แต่คุณกำลังทำตามมาตรฐาน! Sql-case เป็นกรณีเฉพาะเช่นกันดังนั้นจึงต้องการวิธีแก้ปัญหาที่ค่อนข้างเฉพาะเจาะจง

อย่างไรก็ตาม enum จะสามารถนำกลับมาใช้ใหม่ได้ภายในSystem.Dataพื้นที่ของคุณและนั่นคือสิ่งที่เป็นรูปแบบ

อีกกรณีหนึ่งที่ต้องดูด้วย "Type" คือ "Animal" โดยที่ Type กำหนดสายพันธุ์

public class Animal
    {
        public enum Type
        {
            Mammal,
            Reptile,
            JonSkeet
        }

        public Type Species{ get; set; }

    }

นี่เป็นไปตามรูปแบบคุณไม่จำเป็นต้อง "รู้" วัตถุสำหรับสิ่งนี้โดยเฉพาะและคุณไม่ได้ระบุ "AnimalType" หรือ "DataReaderType" คุณสามารถใช้ enums ซ้ำในเนมสเปซที่คุณเลือกได้


1
ฉันเชื่อว่าชื่อ "สถานะ" เป็นเพียงตัวอย่าง แล้วสถานการณ์อื่น ๆ เมื่อคุณไม่สามารถพึ่งพา Status / State ได้ล่ะ? เช่น Type enum ...
Dan C.

2
@Filip: ตัวอย่าง Animal Type ชี้ให้เห็นว่าฉันหมายถึงอะไรในความคิดเห็นแรกนั่นคือ "rewording" ของ enum ค่อนข้างมาก ฉันคิดว่าการใช้คำพ้องความหมายสำหรับ enum และชื่อคุณสมบัติทำให้รหัสค่อนข้างสับสนฉันคิดว่า
แดนค

1
ฉันยังคิดว่า 'สปีชีส์' เป็นเพียงการเปลี่ยนประเภท (สำหรับสัตว์ในกรณีนี้)
LegendLength

2
การเปลี่ยนชื่อเพียงอย่างเดียวไม่ได้สะอาดเสมอไป - ลองนึกถึงคลาสสำหรับการ์ดเล่นเช่น enum Suit และ Property Suit - เปลี่ยนชื่อเป็นอะไรกันแน่? เงอะงะทางใดทางหนึ่ง
annakata

1
วิธีนี้นำไปสู่ความเข้าใจผิดและทำให้โค้ด
สับสน

9

ฉันคิดว่าปัญหาที่แท้จริงที่นี่คือสถานะ enum ถูกห่อหุ้มภายในชั้นเรียนของคุณซึ่งCar.Statusมีความคลุมเครือทั้งคุณสมบัติStatusและ enumStatus

ยังดีกว่าวาง enum ของคุณไว้นอกชั้นเรียน:

public enum Status
{
    Off,
    Starting,
    Moving
}

public class Car
{
    public Status Status
    { ... }
}

อัปเดต

เนื่องจากความคิดเห็นด้านล่างฉันจะอธิบายการออกแบบของฉันด้านบน

ฉันเป็นคนหนึ่งที่ไม่เชื่อว่า enums หรือคลาสหรืออ็อบเจกต์อื่น ๆ ควรอยู่ในคลาสอื่นเว้นแต่มันจะเป็นส่วนตัวทั้งหมดในคลาสนั้น ยกตัวอย่างข้างต้นเช่น:

public class Car
{
    public enum Status
    {...}
    ...
    public Status CarStatus { get; set;}
}

ในขณะที่ผู้แสดงความคิดเห็นบางคนอาจโต้แย้งว่าสถานะไม่มีความหมายใด ๆ นอกขอบเขตของคลาส Car แต่การที่คุณตั้งค่าทรัพย์สินสาธารณะหมายความว่ามีส่วนอื่น ๆ ของโปรแกรมที่จะใช้ enum นั้น:

public Car myCar = new Car();
myCar.CarStatus = Car.Status.Off;

และนั่นคือกลิ่นรหัส ถ้าฉันจะไปดูที่สถานะที่ด้านนอกของCarผมเช่นกันอาจจะกำหนดมันนอกเช่นกัน

ดังนั้นฉันอาจจะเปลี่ยนชื่อเป็น:

public enum CarStatus
{...}

public class Car
{
    ...
    public CarStatus Status { get; set; }
}

อย่างไรก็ตามหาก enum นั้นจะถูกใช้ภายในและเฉพาะในคลาสรถยนต์ฉันก็สบายดีที่จะประกาศ enum ที่นั่น


นั่นจะทำให้สถานะเป็นสากลคุณอาจต้องการให้มันอยู่ในพื้นที่เฉพาะ "สถานะ" สำหรับประเภทอื่น ๆ เช่น "มนุษย์" อาจไม่มี "กำลังเริ่ม" แต่คุณควรทำตามรูปแบบ
Filip Ekberg

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

จอนนี่คือประเด็นของฉันอย่างแม่นยำ: สถานะ enum มีความหมายเกี่ยวกับรถยนต์เท่านั้น วัตถุประเภทต่างๆโดยสิ้นเชิงจะมีสถานะที่แตกต่างกันโดยสิ้นเชิง
Serge Wautier

พวกเขาจะอยู่ในเนมสเปซที่แตกต่างกันดังนั้นมันก็ไม่สำคัญ
Chris S

คำอธิบายที่อยากให้มองภายนอกคาร์เข้าท่า แต่ในกรณีของฉันฉันมีสองคลาสORและCR. ทั้งสองมีชุดสถานะของตนเองดังนั้นจึงไม่ใช่ตัวเลือกที่จะกำหนดสถานะภายนอกขอบเขตของตนเอง
โฉนด02392

4

ฉันรู้ว่าข้อเสนอแนะของฉันขัดต่อหลักการตั้งชื่อ. ฉันไม่เข้าใจจริงๆว่าทำไมถึงไม่เป็นแบบนี้ Enums / Flags เป็นกรณีพิเศษเช่นอินเทอร์เฟซที่จะไม่เปลี่ยนประเภท ไม่เพียง แต่จะทำให้ชัดเจนว่ามันคืออะไรการพิมพ์ intellisense นั้นง่ายมากเนื่องจากคำนำหน้าจะกรองประเภท / ตัวแปร / ฯลฯ ส่วนใหญ่และคุณจะไม่มีข้อขัดแย้งในการตั้งชื่อเหล่านี้

และนั่นจะช่วยแก้ปัญหาอีกประการหนึ่งโดยที่ตัวอย่างใน WPF ใช้คลาสแบบคงที่เช่น enums (เช่น FontWeights) ที่มีอินสแตนซ์ประเภทที่กำหนดไว้ล่วงหน้า แต่คุณจะไม่รู้ว่าคุณไม่ได้ค้นหาหรือไม่ หากพวกเขาขึ้นต้นด้วย 'E' สิ่งที่คุณต้องทำคือพิมพ์ตัวอักษรเพื่อค้นหาคลาสคงที่พิเศษเหล่านี้


4

ผู้เกลียดชังสัญกรณ์ฮังการีและรูปแบบต่างๆได้รับความเสียหาย ผมใช้การประชุมของ suffixing enums กับ - การรอคอยสำหรับมัน Enum- ดังนั้นฉันจึงไม่เคยมีปัญหาที่คุณอธิบายเสียเวลากังวลว่าจะเรียกพวกเขาว่าอะไรและรหัสนั้นอ่านได้และอธิบายได้ด้วยตนเอง

public class Car
{
  public enum StatusEnum
  {
    Off,
    Starting,
    Moving
  };

  public StatusEnum Status { get; set; }

}

9
โปรดทราบว่าอนุสัญญาของ Microsoft สำหรับNaming Enumerationsกล่าวว่า: X ห้าม ใช้คำต่อท้าย "Enum" ในชื่อประเภท enum
DavidRR

2
เนื่องจากอนุสัญญาของ Microsoft ได้รับการพิสูจน์แล้วว่าสามารถยืนหยัดได้ตลอดเวลา
nathanchere


1

ฉันขอแนะนำให้เพิ่ม "ตัวเลือก" ในชื่อประเภท (หรือตั้งค่าสถานะหากมีแฟล็กบิต) เช่นประเภทคือ Car.StatusOption และคุณสมบัติคือ Car.Status

เมื่อเทียบกับ pluralizing หลีกเลี่ยงการตั้งชื่อนี้ชนกันเมื่อมีการสร้างคอลเลกชันของประเภท enum ที่คุณมักจะต้องการที่จะ pluralize คอลเลกชันคุณสมบัติไม่ enum ประเภท


0

ฉันมักจะนำหน้า enums เช่น CarStatus ฉันคิดว่าทุกอย่างขึ้นอยู่กับทีมที่คุณทำงานด้วย (หากพวกเขามีกฎ / กระบวนการใด ๆ สำหรับสิ่งนั้น) และการใช้วัตถุ แค่ 2 เซ็นต์ของฉัน (:


1
นั่นจะเป็นการฆ่าหลักการตั้งชื่อที่มี MyObjectName อยู่หน้าสถานะ
Filip Ekberg

namespacing จากชั้นเรียนควรจะเพียงพอที่จะรับมือกับเรื่องนี้อยู่แล้ว
annakata
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.