2011-09-16 27 views
37

Tôi có thể bỏ lỡ một số điểm ở đây, nếu đó là trường hợp - vui lòng bao gồm cuộc thảo luận đó như là một phần của câu hỏi của tôi :).Enum với các phương pháp cho chức năng (Kết hợp Class/Enum)

Đây là mẫu rút gọn và được đổi tên thành mã hoạt động. GetTicks (..) là một mẫu đơn, có thể là bất kỳ loại chức năng nào (giá trị của > 0 < 9 phải trả về một Enum a.so cụ thể).

public static class Something 
{ 
    public enum TypeOf : short 
    { 
     Minute = 2, Hour = 3, Day = 4, ........ 
    } 

    public static long GetTicks(Something.TypeOf someEnum) 
    { 
     long ticks = 0; 
     switch (someEnum) 
     { 
      case Something.TypeOf.Minute: 
       ticks = TimeSpan.TicksPerMinute; 
       break; 
      case Something.TypeOf.Hour: 
       ticks = TimeSpan.TicksPerHour; 
       break; 
     .... 
     } 
     return ticks; 
    } 
} 


// This class is called from anywhere in the system. 
public static void SomeMethod(string dodo, object o, Something.TypeOf period) 
{ 
    // With the design above 
    long ticks = Something.GetTicks(period); 

    // Traditional, if there was a simple enum 
    if (period == Something.Day) 
     ticks = TimeSpan.FromDays(1).Ticks; 
    else if (period == Something.Hour) 
     ticks = TimeSpan.FromHours(1).Ticks; 
} 

Ý tưởng là thu thập chức năng liên quan đến enum, gần nhất có thể với bản thân enum. Enum là hàm lý do. Ngoài ra tôi tìm thấy nó dễ dàng và tự nhiên để tìm các chức năng như vậy gần enum. Ngoài ra, thật dễ dàng để sửa đổi hoặc mở rộng.

Hạn chế tôi có, là tôi phải nêu rõ enum rõ ràng hơn Something.TypeOf. Thiết kế có thể trông không chuẩn? và sẽ áp dụng nếu enum là để sử dụng nội bộ trong lớp.

Bạn sẽ làm điều này tốt hơn như thế nào? Tôi đã cố gắng trừu tượng, thừa kế cơ sở, một phần. Không ai trong số họ dường như áp dụng.

Trả lời

32

C# enums không hoạt động tốt như thế này. Tuy nhiên, bạn có thể thực hiện "tập cố định các giá trị" của riêng bạn khá dễ dàng:

public sealed class Foo 
{ 
    public static readonly Foo FirstValue = new Foo(...); 
    public static readonly Foo SecondValue = new Foo(...); 

    private Foo(...) 
    { 
    } 

    // Add methods here 
} 

Vì nó xảy ra, một ví dụ tôi đã có của việc này là đáng kể tương tự như của bạn - DateTimeFieldType trong Noda Time. Đôi khi bạn thậm chí có thể muốn làm cho lớp chưa được niêm phong, nhưng giữ hàm tạo riêng - cho phép bạn tạo các lớp con chỉ như các lớp lồng nhau. Rất tiện dụng để hạn chế thừa kế.

Nhược điểm là bạn không thể sử dụng công tắc :(

+0

Thực sự hoàn toàn giống nhau! Tôi thích cách tiếp cận của bạn và sẽ đào sâu vào nó sau này khi tôi có thể nhận biết thời gian để tối ưu hóa và hiểu lợi ích của nó (nếu một số);)). – Independent

+0

Vâng, các enums giống Java. Mặc dù tôi khuyên bạn nên sử dụng một cấu trúc, không phải là một lớp học. Và trường _Value_ để so sánh nhanh và câu lệnh chuyển đổi. – IllidanS4

+0

@ IllidanS4: Tôi thấy không có đặc biệt để sử dụng một cấu trúc - và một lớp cho phép các lớp con khác nhau thực hiện hành vi khác nhau (giống như Java enums). Ngoài ra, một cấu trúc có nghĩa là 'mặc định (Foo)' luôn luôn là một giá trị "thực", có thể là một cơn đau ở cổ. Trong khi tôi chắc chắn có những trường hợp mà một phiên bản struct sẽ là thích hợp, tôi thường xuyên sử dụng các lớp học. –

71

Nếu bạn không nhớ một chút viết nhiều hơn, bạn có thể tạo ra một phương pháp khuyến nông để mở rộng giao diện của enum.

ví dụ

public enum TimeUnit 
{ 
    Second, 
    Minute, 
    Hour, 
    Day, 
    Year, 
    /* etc */ 
} 
public static class TimeUnitExtensions 
{ 
    public static long InTicks(this TimeUnit myUnit) 
    { 
     switch(myUnit) 
     { 
      case TimeUnit.Second: 
       return TimeSpan.TicksPerSecond; 
      case TimeUnit.Minute: 
       return TimeSpan.TicksPerMinute; 
      /* etc */ 
     } 
    } 
} 

này có thể thêm "dụ" phương pháp để enums của bạn. Đó là tiết hơn một chút so với hầu hết giống như mặc dù.

Ghi dù một enum cần được điều trị chủ yếu như một giá trị được đặt tên.

+0

Làm thế nào để bạn liên kết 'TimeUnitExtensions' thành' TimeUnit' và thể hiện 'TimeSpan' mà bạn muốn bọ ve? Tôi có thể thiếu một số bối cảnh và không nghi ngờ gì về việc thiếu kiến ​​thức C# của tôi không giúp ích gì. –

+2

@DavidHarkness, đó là vì "điều này" trong dòng này: công cộng tĩnh dài InTicks (này TimeUnit myUnit). "This" liên kết TimeUnit thành phần mở rộng. – Seva

+0

Tôi thích câu trả lời của Jon, nhưng đây cũng là một khả năng. 1, tôi đã không được coi là phương pháp mở rộng cho việc này! – Joel

Các vấn đề liên quan