Nếu một cố gắng để tạo ra một cấu trúc chung với thuộc tính [ StructLayout (LayoutKind .Explicit)]
, sử dụng các cấu trúc tạo ra một ngoại lệ trong thời gian chạy:Tại sao các loại chung chung không có bố cục rõ ràng?
System.TypeLoadException: Không thể nạp kiểu 'foo' từ 'bar' lắp ráp vì kiểu generic không thể có bố cục rõ ràng.
Tôi đã gặp khó khăn khi tìm bất kỳ bằng chứng nào cho thấy hạn chế này thậm chí còn tồn tại. Tài liệu Type.IsExplicitLayout
mạnh mẽ ngụ ý rằng nó được cho phép và hỗ trợ. Có ai biết tại sao điều này không được phép? Tôi không thể nghĩ ra bất kỳ lý do gì tại sao các loại chung loại sẽ làm cho nó ít có thể kiểm chứng được. Nó đánh tôi như là một trường hợp cạnh mà họ chỉ đơn giản là không bận tâm để thực hiện.
Dưới đây là an example tại sao rõ ràng bố trí chung sẽ có ích:
public struct TaggedUnion<T1,T2>
{
public TaggedUnion(T1 value) { _union=new _Union{Type1=value}; _id=1; }
public TaggedUnion(T2 value) { _union=new _Union{Type2=value}; _id=2; }
public T1 Type1 { get{ if(_id!=1)_TypeError(1); return _union.Type1; } set{ _union.Type1=value; _id=1; } }
public T2 Type2 { get{ if(_id!=2)_TypeError(2); return _union.Type2; } set{ _union.Type2=value; _id=2; } }
public static explicit operator T1(TaggedUnion<T1,T2> value) { return value.Type1; }
public static explicit operator T2(TaggedUnion<T1,T2> value) { return value.Type2; }
public static implicit operator TaggedUnion<T1,T2>(T1 value) { return new TaggedUnion<T1,T2>(value); }
public static implicit operator TaggedUnion<T1,T2>(T2 value) { return new TaggedUnion<T1,T2>(value); }
public byte Tag {get{ return _id; }}
public Type GetUnionType() {switch(_id){ case 1:return typeof(T1); case 2:return typeof(T2); default:return typeof(void); }}
_Union _union;
byte _id;
void _TypeError(byte id) { throw new InvalidCastException(/* todo */); }
[StructLayout(LayoutKind.Explicit)]
struct _Union
{
[FieldOffset(0)] public T1 Type1;
[FieldOffset(0)] public T2 Type2;
}
}
sử dụng:
TaggedUnion<int, double> foo = 1;
Debug.Assert(foo.GetUnionType() == typeof(int));
foo = 1.0;
Debug.Assert(foo.GetUnionType() == typeof(double));
double bar = (double) foo;
Edit:
Để được rõ ràng, lưu ý rằng bố trí không được xác nhận tại thời gian biên dịch ngay cả khi cấu trúc không phải là chung chung. Sự khác nhau về tham chiếu chồng lên nhau và x64 được phát hiện trong thời gian chạy bởi CLR: http://pastebin.com/4RZ6dZ3S Tôi hỏi tại sao generics bị hạn chế khi kiểm tra được thực hiện khi chạy theo một trong hai cách.
Đối với hồ sơ, cùng một loại "áp đặt hạn chế" có thể được thực hiện bằng cách ném từ các nhà xây dựng tĩnh. (Và tôi sẽ không ngạc nhiên khi thấy điều đó được thực hiện trong thực tế vì những hạn chế chung là vô lý.) Nhưng tôi đoán tôi sẽ không ngạc nhiên nếu đó thực sự là lý do của họ cho giới hạn này. – DBN
@DBN - Tôi đoán đó thực sự là lý do, nếu không người ta có thể lập luận rằng hệ thống ràng buộc kiểu có thể được tung ra thay cho ngoại lệ. Tôi cũng đồng ý với bạn, họ không đủ mạnh. Về mặt tươi sáng, việc triển khai C#/CTS dễ viết hơn nhiều so với C++. Là một nhà biên dịch trình biên dịch, tôi thực tế có thể có cơ hội thực hiện ngôn ngữ của riêng tôi với các CTS generics mà không cần sự trợ giúp. Với các mẫu C++, bạn nên có một nhóm với bạn. Tôi phải thừa nhận, C# là một thiết kế tương đối sạch sẽ. – codenheim
Tôi không thấy bất kỳ đường dẫn tốt nào để thêm bất kỳ loại ràng buộc chung nào vào hệ thống kiểu, mà giả định một tập hợp rất cố định của những người không kế thừa [mới, cấu trúc và lớp]. Mặc dù có thể hữu ích khi có một hạn chế cho ví dụ: "có thể sao chép thành giá trị" (làm cho nó có thể định nghĩa các cấu trúc * không *), không có ràng buộc chung nào hiện đang yêu cầu nó, và do đó không có kiểu generic nào có thể thỏa mãn nó. Điều có lẽ sẽ là cần thiết để có một hạn chế chống lại, như vậy mà các cấu trúc không được sao chép-như-giá trị có thể * chỉ * được chuyển cho các tham số chung ... – supercat