[Lưu ý: Câu hỏi này có tiêu đề ban đầu là " C (ish) style union in C # " nhưng như nhận xét của Jeff đã cho tôi biết, rõ ràng cấu trúc này được gọi là 'liên hiệp phân biệt đối xử']
Xin lỗi về sự dài dòng của câu hỏi này.
Có một vài câu hỏi nghe tương tự với tôi đã có trong SO nhưng chúng dường như tập trung vào lợi ích tiết kiệm bộ nhớ của liên minh hoặc sử dụng nó cho tương tác. Đây là một ví dụ về một câu hỏi như vậy .
Mong muốn của tôi là có một loại hình công đoàn hơi khác.
Tôi đang viết một số mã tại thời điểm này tạo ra các đối tượng trông giống như thế này
public class ValueWrapper
{
public DateTime ValueCreationDate;
// ... other meta data about the value
public object ValueA;
public object ValueB;
}
Những thứ khá phức tạp tôi nghĩ bạn sẽ đồng ý. Vấn đề là nó ValueA
chỉ có thể thuộc một số loại nhất định (giả sử string
, int
và Foo
(đó là một lớp) và ValueB
có thể là một nhóm nhỏ các loại khác. Tôi không thích coi những giá trị này là đối tượng (tôi muốn cảm giác ấm áp vừa khít của mã hóa với một chút về kiểu an toàn).
Vì vậy, tôi đã nghĩ đến việc viết một lớp trình bao bọc nhỏ tầm thường để thể hiện sự thật rằng ValueA một cách hợp lý là một tham chiếu đến một kiểu cụ thể. Tôi gọi cho lớp học Union
vì những gì tôi đang cố gắng đạt được nhắc nhở tôi về khái niệm công đoàn trong C.
public class Union<A, B, C>
{
private readonly Type type;
public readonly A a;
public readonly B b;
public readonly C c;
public A A{get {return a;}}
public B B{get {return b;}}
public C C{get {return c;}}
public Union(A a)
{
type = typeof(A);
this.a = a;
}
public Union(B b)
{
type = typeof(B);
this.b = b;
}
public Union(C c)
{
type = typeof(C);
this.c = c;
}
/// <summary>
/// Returns true if the union contains a value of type T
/// </summary>
/// <remarks>The type of T must exactly match the type</remarks>
public bool Is<T>()
{
return typeof(T) == type;
}
/// <summary>
/// Returns the union value cast to the given type.
/// </summary>
/// <remarks>If the type of T does not exactly match either X or Y, then the value <c>default(T)</c> is returned.</remarks>
public T As<T>()
{
if(Is<A>())
{
return (T)(object)a; // Is this boxing and unboxing unavoidable if I want the union to hold value types and reference types?
//return (T)x; // This will not compile: Error = "Cannot cast expression of type 'X' to 'T'."
}
if(Is<B>())
{
return (T)(object)b;
}
if(Is<C>())
{
return (T)(object)c;
}
return default(T);
}
}
Sử dụng lớp ValueWrapper này bây giờ trông như thế này
public class ValueWrapper2
{
public DateTime ValueCreationDate;
public Union<int, string, Foo> ValueA;
public Union<double, Bar, Foo> ValueB;
}
đó là một cái gì đó giống như những gì tôi muốn đạt được nhưng tôi thiếu một yếu tố khá quan trọng - đó là kiểm tra kiểu bắt buộc của trình biên dịch khi gọi hàm Is và As như đoạn mã sau minh họa
public void DoSomething()
{
if(ValueA.Is<string>())
{
var s = ValueA.As<string>();
// .... do somethng
}
if(ValueA.Is<char>()) // I would really like this to be a compile error
{
char c = ValueA.As<char>();
}
}
IMO Không hợp lệ khi hỏi ValueA nếu đó là một char
vì định nghĩa của nó nói rõ ràng là không - đây là một lỗi lập trình và tôi muốn trình biên dịch khắc phục lỗi này. [Ngoài ra nếu tôi có thể hiểu đúng điều này thì (hy vọng) tôi cũng sẽ nhận được intellisense - đó sẽ là một lợi ích.]
Để đạt được điều này, tôi muốn nói với trình biên dịch rằng kiểu T
có thể là một trong A, B hoặc C
public bool Is<T>() where T : A
or T : B // Yes I know this is not legal!
or T : C
{
return typeof(T) == type;
}
Có ai có bất kỳ ý tưởng nếu những gì tôi muốn đạt được là có thể? Hay tôi chỉ đơn giản là ngu ngốc khi viết lớp này ngay từ đầu?
Cảm ơn trước.
StructLayout(LayoutKind.Explicit)
vàFieldOffset
. Tất nhiên, điều này không thể được thực hiện với các loại tham chiếu. Những gì bạn đang làm không giống C Union chút nào.