[注:この質問の元のタイトルは「C#でのC(ish)スタイルの共用体」でしたが、Jeffのコメントで通知されたように、この構造は明らかに「差別化された共用体」と呼ばれます]
この質問の冗長さをすみません。
すでに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;
}
これは私が達成したいもののようなものですが、かなり重要な要素が1つありません。それは、次のコードが示すように、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 char
その定義で明らかにそうではないため、ValueAがaであるかどうかを尋ねることは有効ではありません。これはプログラミングエラーであり、コンパイラーがこれを取得できるようにしたいと考えています。[また、これを正しく取得できれば(うまくいけば)インテリセンスも得られるでしょう-これは朗報です。]
これを達成するために、タイプ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;
}
私が達成したいことが可能である場合、誰かが何か考えを持っていますか?それとも、このクラスを最初から書いているのは私だけなのでしょうか?
前もって感謝します。
StructLayout(LayoutKind.Explicit)
およびを使用して、値型のC#で実装できますFieldOffset
。もちろん、これは参照型では実行できません。あなたがやっていることは、C連合のようなものではありません。