[Note: Cette question avait le titre original "C (ish) style de l'union en C#" mais comme Jeff commentaire m'a informé, apparemment, cette structure est appelée une " victime de l'est de l'union]
Excuse le niveau de détail de cette question.
Il y a un couple qui se ressemblent questions à mine de, dans la mais ils semblent se concentrer sur la mémoire des économies de l'union ou de l'utiliser pour l'interopérabilité. Voici un exemple d'une telle question.
Mon désir d'avoir une union de type de chose est un peu différente.
Je suis en train d'écrire un peu de code pour le moment qui génère des objets qui ressemblent un peu à ce
public class ValueWrapper
{
public DateTime ValueCreationDate;
// ... other meta data about the value
public object ValueA;
public object ValueB;
}
Assez compliqué tout ça je pense que vous serez d'accord. Le truc, c'est qu' ValueA
ne peut être d'un peu de certains types (disons string
, int
et Foo
(qui est une classe) et ValueB
peut-être un autre petit ensemble de types. Je n'aime pas le traitement de ces valeurs comme des objets (je veux du chaud confortablement sentiment de codage avec un peu de type de sécurité).
J'ai donc pensé à écrire un trivial peu de classe wrapper pour exprimer le fait que ValueA logiquement est une référence à un type particulier. J'ai appelé la classe Union
parce que ce que je suis en train de réaliser me rappelle de l'union concept en 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);
}
}
À l'aide de cette classe ValueWrapper ressemble maintenant à ceci
public class ValueWrapper2
{
public DateTime ValueCreationDate;
public Union<int, string, Foo> ValueA;
public Union<double, Bar, Foo> ValueB;
}
qui est quelque chose comme ce que je voulais obtenir mais il me manque une assez élément essentiel - c'est-à compilateur forcée type de vérification lors de l'appel de l'Est et en tant Que fonctions, comme l'illustre le code suivant
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 Il n'est pas valable pour demander ValueA si c'est un char
depuis sa définition clairement dit qu'il n'est pas - c'est une erreur de programmation et je voudrais le compilateur pour ramasser sur ce. [Aussi, si je pouvais avoir ce correcte (je l'espère), je voudrais obtenir intellisense trop - ce qui serait une aubaine.]
Afin d'atteindre ce que je voudrais dire au compilateur que le type T
peut être l'un des A, B ou 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;
}
Quelqu'un a une idée si ce que je veux réaliser est possible? Ou suis-je tout simplement stupide pour l'écriture de cette classe à la première place?
Merci à l'avance.