[Not: Bu sorunun orijinal başlığı " C # 'de C (ish) tarzı birleşme " idi, ancak Jeff'in yorumunun bana bildirdiği gibi, görünüşe göre bu yapıya "ayrımcılığa dayalı birleşme" deniyor]
Bu sorunun ayrıntıları için özür dilerim.
SO'da benim için benzer sesli sorular var, ancak sendikanın hafıza tasarrufu yararlarına veya birlikte çalışma için kullanmaya odaklanmış gibi görünüyorlar. İşte böyle bir soruya bir örnek .
Sendika tipi bir şeye sahip olma arzum biraz farklı.
Şu anda biraz buna benzeyen nesneler üreten bir kod yazıyorum
public class ValueWrapper
{
public DateTime ValueCreationDate;
// ... other meta data about the value
public object ValueA;
public object ValueB;
}
Oldukça karmaşık konulara katılacağınızı düşünüyorum. Şey yani ValueA
sadece (let diyelim birkaç belirli tipte olabilir string
, int
ve Foo
bir sınıf olan () ve ValueB
türleri başka bir küçük kümesi olabilir. (Ben sıcak sıkı bir şekilde duygu istediğiniz nesneleri olarak bu değerleri tedavi sevmiyorum biraz güvenlikli kodlama).
Bu yüzden, ValueA'nın mantıksal olarak belirli bir türe referans olduğu gerçeğini ifade etmek için önemsiz, küçük bir sarmalayıcı sınıfı yazmayı düşündüm. Sınıfı aradım Union
çünkü başarmaya çalıştığım şey bana C'deki sendika konseptini hatırlattı.
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);
}
}
Bu sınıf ValueWrapper'ı kullanmak artık buna benziyor
public class ValueWrapper2
{
public DateTime ValueCreationDate;
public Union<int, string, Foo> ValueA;
public Union<double, Bar, Foo> ValueB;
}
bu, elde etmek istediğim şey gibi bir şey ama oldukça önemli bir unsuru kaçırıyorum - bu, aşağıdaki kodun gösterdiği gibi Is ve As işlevlerini çağırırken derleyicinin zorunlu kıldığı tür denetimi
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'ya bir olup olmadığını sormak geçerli değildir char
çünkü tanımı açıkça öyle olmadığını söylüyor - bu bir programlama hatası ve derleyicinin bunu almasını istiyorum. [Ayrıca bunu doğru yapabilseydim (umarım) zeka da alırdım - bu bir nimet olurdu.]
Bunu başarmak için derleyiciye türün T
A, B veya C'den biri olabileceğini söylemek isterim.
public bool Is<T>() where T : A
or T : B // Yes I know this is not legal!
or T : C
{
return typeof(T) == type;
}
Başarmak istediğim şeyin mümkün olup olmadığı konusunda herhangi bir fikri olan var mı? Yoksa en başta bu dersi yazdığım için aptal mıyım?
Şimdiden teşekkürler.
StructLayout(LayoutKind.Explicit)
ve kullanılarak değer türleri için C # 'da uygulanabilirFieldOffset
. Bu tabii ki referans türleri ile yapılamaz. Yaptığın şey hiç bir C Birliği gibi değil.