но, как сообщил мне комментарий Джеффа, по-видимому, эта структура называется «дискриминируемым объединением»]
Извините за многословие этого вопроса.
У меня уже есть несколько похожих по звучанию вопросов в SO, но они, похоже, концентрируются на преимуществах объединения памяти или его использовании для interop.
Вот пример такого вопроса.
Мое желание иметь тип объединения несколько иное.
Сейчас я пишу код, который генерирует объекты, которые выглядят примерно так.
Код: Выделить всё
public class ValueWrapper
{
public DateTime ValueCreationDate;
// ... other meta data about the value
public object ValueA;
public object ValueB;
}
Поэтому я подумал о написании тривиального небольшого класса-оболочки, чтобы выразить тот факт, что ValueA логически является ссылку на определенный тип. Я назвал класс Union, потому что то, чего я пытаюсь достичь, напомнило мне концепцию объединения в C.
Код: Выделить всё
public class Union
{
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;
}
///
/// Returns true if the union contains a value of type T
///
/// The type of T must exactly match the type
public bool Is()
{
return typeof(T) == type;
}
///
/// Returns the union value cast to the given type.
///
/// If the type of T does not exactly match either X or Y, then the value default(T) is returned.
public T As()
{
if(Is())
{
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())
{
return (T)(object)b;
}
if(Is())
{
return (T)(object)c;
}
return default(T);
}
}
Код: Выделить всё
public class ValueWrapper2
{
public DateTime ValueCreationDate;
public Union ValueA;
public Union ValueB;
}
Код: Выделить всё
public void DoSomething()
{
if(ValueA.Is())
{
var s = ValueA.As();
// .... do somethng
}
if(ValueA.Is()) // I would really like this to be a compile error
{
char c = ValueA.As();
}
}
Чтобы добиться этого, я хотел бы сообщить компилятору, что тип T может быть одним из A, B или C
Код: Выделить всё
public bool Is() where T : A
or T : B // Yes I know this is not legal!
or T : C
{
return typeof(T) == type;
}