[注意:这个问题的原标题是“ C# 中的 C (ish) style union ”,但正如 Jeff 的评论告诉我的,显然这个结构被称为“discriminated union”]
原谅这个问题的冗长。
在 SO 中已经有几个类似的问题需要挖掘,但它们似乎专注于联合的内存节省优势或将其用于互操作。 这是一个这样的问题的例子。
我想要一个联合类型的东西有点不同。
我现在正在编写一些代码,它生成看起来有点像这样的对象
public class ValueWrapper
{
public DateTime ValueCreationDate;
// ... other meta data about the value
public object ValueA;
public object ValueB;
}
相当复杂的东西我想你会同意的。问题是它ValueA
只能是几种特定类型(比如说string
,int
和Foo
(这是一个类),并且ValueB
可以是另一小组类型。我不喜欢将这些值视为对象(我想要温暖舒适的感觉带有一点类型安全性的编码)。
所以我想写一个简单的小包装类来表达 ValueA 在逻辑上是对特定类型的引用这一事实。我打电话给这门课Union
是因为我想要达到的目标让我想起了 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);
}
}
使用这个类 ValueWrapper 现在看起来像这样
public class ValueWrapper2
{
public DateTime ValueCreationDate;
public Union<int, string, Foo> ValueA;
public Union<double, Bar, Foo> ValueB;
}
这与我想要实现的目标相似,但我缺少一个相当关键的元素 - 即在调用 Is 和 As 函数时编译器强制类型检查,如下代码所示
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 询问 ValueA 是否是 a 是无效的,char
因为它的定义清楚地表明它不是 - 这是一个编程错误,我希望编译器能够解决这个问题。[另外,如果我能做到这一点,那么(希望)我也会得到智能感知——这将是一个福音。]
为了实现这一点,我想告诉编译器类型T
可以是 A、B 或 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;
}
有谁知道我想要实现的目标是否可行?还是我一开始就写这门课是愚蠢的?
提前致谢。