[참고 :이 질문의 원래 제목은 " C #의 C (ish) 스타일 결합 "이지만 Jeff의 의견에 따르면이 구조는 '차별 결합'이라고합니다.]
이 질문의 장황함을 용서하십시오.
이미 SO에서 내 것과 비슷한 몇 가지 질문이 있지만 그들은 노동 조합의 메모리 절약 이점에 집중하거나 interop에 사용하는 것 같습니다. 다음은 그러한 질문의 예입니다 .
유니온 타입의 것을 갖고 싶다는 욕망은 다소 다릅니다.
지금은 이와 비슷한 개체를 생성하는 코드를 작성 중입니다.
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에게 그것이 char
정의되어 있지 않다고 분명히 말하고 있기 때문에 ValueA에게 묻는 것은 유효하지 않습니다. 이것은 프로그래밍 오류이며 컴파일러가 이것을 선택하기를 바랍니다. [또한 내가 이것을 맞출 수 있다면 (희망적으로) 나도 지능을 얻게 될 것입니다. 이것은 이익이 될 것입니다.]
이를 달성하기 위해 컴파일러에게 유형 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)
와FieldOffset
. 물론 참조 유형으로는 수행 할 수 없습니다. 당신이하는 일은 전혀 C 연합과 같지 않습니다.