Các C# enum là vô ích.
Bạn có thể tránh truyền từ loại của bạn VÀ hạn chế các giá trị có thể được đúc một cách rõ ràng với loại của bạn bằng cách tạo lớp kín và cung cấp toán tử chuyển đổi ngầm/rõ ràng.
- Cung cấp toán tử ngầm để chuyển đổi từ loại của bạn thành int chung để bạn không phải truyền.
- Cung cấp toán tử rõ ràng để chuyển đổi từ int sang loại của bạn, lỗi này nếu số nguyên không đáp ứng được ràng buộc, chẳng hạn như (int x) => (x> = 0 & & x < = 2).
Nếu sử dụng kỹ thuật này, tạo ra một generic bất biến lớp cơ sở như ConstrainedNumber<T>
, trong đó có một nhà xây dựng mà chấp nhận một giá trị T và đại biểu cho sự hạn chế: delegate bool NumberConstraint<T>(T value)
. Hàm khởi tạo nên chạy giá trị thông qua ủy nhiệm hạn chế và ném một ngoại lệ nếu nó không đáp ứng được ràng buộc. Lớp cơ sở cũng nên xử lý hoạt động chuyển đổi ngầm định thành T và cần xử lý bình đẳng bằng cách nạp chồng đối tượng.Equals (object) và object.GetHashCode(), định nghĩa == và! = Toán tử cho loại ConstrainedNumber<T>
và triển khai IEquatable<T>
và IEquatable<ConstrainedNumber<T>>
. Tôi cũng khuyên bạn nên định nghĩa một hàm tạo bản sao cho lớp cơ sở và tất cả các kiểu có nguồn gốc. Nhân bản sau đó có thể được thực hiện một cách sạch sẽ trong lớp cơ sở bằng cách truy xuất hàm tạo bản sao thông qua sự phản chiếu, nhưng điều này hoàn toàn là tùy chọn. Bạn có thể tự mình thực hiện việc thực hiện ConstrainedNumber<T>
, trừ khi tôi đã đăng nó lên stackoverflow ở đâu đó.
Bạn có thể cung cấp giá trị chỉ đọc tĩnh được đặt tên trong ConstrainedNumber bắt nguồn để bạn có thể truy cập chúng giống như một enum.
public sealed class ReturnValue: ConstrainedNumber<int>
{
public static readonly NumberConstraint<int> constraint = (int x) => (x >= 0 && x < 3);
public static readonly ReturnValue Success = new ReturnValue(0);
public static readonly ReturnValue FailReason1 = new ReturnValue(1);
public static readonly ReturnValue FailReason2 = new ReturnValue(2);
private ReturnValue(int value): base(value, constraint) {}
private ReturnValue(ReturnValue original): base (original) {} //may be used to support IClonable implementation in base class
public static explicit operator ReturnValue(int value)
{
switch(value) //switching to return an existing instance is more efficient than creating a new one and re-checking the constraint when there is a limited number of allowed values; if the constraint was more generic, such as an even number, then you would instead return a new instance here, and make your constructors public.
{
case 0: return Success;
case 1: return FailReason1;
case 2: return FailReason2;
}
throw new ArgumentException("Value fails to meet the constraint defined for " + typeof(ReturnValue).FullName + ".", "value");
}
}
Bạn có thể sử dụng kỹ thuật này cho bất kỳ ràng buộc nào. Ví dụ, một lớp được gọi là EvenNumber có thể có một ràng buộc trả về true nếu số đã cho là chẵn. Trong trường hợp đó, bạn chỉ cần tạo các hàm khởi tạo của bạn, và đơn giản hóa toán tử chuyển đổi tĩnh của bạn để trả về một EvenNumber mới, thay vì chuyển đổi để trả về một trong các cá thể có giới hạn hiện có.
Nó có thể được sử dụng như thế này:
EvenNumber x = (EvenNumber)2;
EvenNumber y = (EvenNumber)3; //throws exception "Value fails to meet the constraint defined for {namespace}.EvenNumber." A c# enum would stupidly allow such a cast, creating an invalid EvenNumber, breaking the object-oriented model
int z = x; //implicit conversion, no cast necessary;
Làm việc như một sự quyến rũ, Cảm ơn! Lạ lùng là bạn có thể định nghĩa một enum: "public enum MyEnum: int {...}" và không có giá trị của nó ngầm có thể cast. Không có khái niệm về một "enum chung" là có? - công khai enum MyEnum - hoặc là điều này hoàn toàn vô lý? –
Pwninstein
Bạn có thể delcare gõ vào enum của bạn "enum công cộng ReturnValue: int" mà thi hành rằng các giá trị là loại int. Nó vẫn không cung cấp khả năng truyền ngầm. Chỉnh sửa để hiển thị khi nó _is_ một ý tưởng tốt để sử dụng các giá trị trong một enum. –
Một gợi ý nhỏ - sử dụng 'static readonly int' thay vì' const', trong trường hợp giá trị của bạn thay đổi trong các phiên bản sau. Bạn không muốn người gọi có giá trị đó được biên dịch vào mã của họ. –