Обратите внимание, что человек, похоже, не запрашивает кортеж (тип, который содержит несколько типов, таких как структура стиля c, но без имен), но Tagged Union/Sum type.
A Tuple имеет один из каждого типа, меченый союз содержит только одно значение из двух или более типов.
Пример, который он дал, представляет собой перемычку haxe, которая не похожа на перечисление C# (в основном имена для числа).
От http://haxe.org/ref/enums
Примечание: Haxe Перечисления ведут себя так же, как помечено союзы, что позволяет спецификации и захват каждого «дела» данного результата метода. Поскольку все состояния Enum должны указываться в операторах switch, это делает их ценными для полного определения поведения данного метода, а также для обеспечения того, чтобы эти поведения обрабатывались.
Если вы хотите удостовериться, что каждый случай всегда обрабатывается, не реализуйте единственный метод Action Run в классе ниже.
Кроме того, вы можете избежать имени или как либо (с левым/правым) часто используются конкретно для объединения ошибки или в результате (с остались быть ошибкой или права быть результатом.
здесь одна реализация союза 2 члена.
Вы также можете копию этого для 3,4,5 союза члена с таким же именем
public sealed class Union<A,B,C> : IEquatable<Union<A,B>>
public sealed class Union<A,B,C,D> : IEquatable<Union<A,B,C,D>>
public sealed class Union<A,B,C,D,E> : IEquatable<Union<A,B,C,D,E>>
в структуре приведенной ниже
[Serializable()]
public sealed class Union<A,B> : IEquatable<Union<A,B>>
{
private enum TypeTag{ A, B};
private Union()
{
}
private A AValue;
private B BValue;
private TypeTag tag;
public static Union<A,B> CreateA (A a)
{
var u = new Union<A,B>();
u.AValue = a;
u.tag = TypeTag.A;
return u;
}
public static Union<A,B> CreateB (B b)
{
var u = new Union<A,B>();
u.BValue = b;
u.tag = TypeTag.B;
return u;
}
public U SelectOn<U> (Func<A, U> withA, Func<B, U> withB)
{
if (withA == null)
throw new ArgumentNullException ("withA");
if (withB == null)
throw new ArgumentNullException ("withB");
if (tag == TypeTag.A)
{
return withA (AValue);
}
else if (tag == TypeTag.B)
{
return withB (BValue);
}
throw new InvalidOperationException ("Unreachable code.");
}
public void Run (Action<A> actionIfA, Action<B> actionIfB)
{
if (actionIfA == null)
throw new ArgumentNullException ("actionIfA");
if (actionIfB == null)
throw new ArgumentNullException ("actionIfB");
if (tag == TypeTag.A)
{
actionIfA (AValue);
}
else if (tag == TypeTag.B)
{
actionIfB (BValue);
}
}
public void Run (Action<A> actionIfA)
{
if (actionIfA == null)
throw new ArgumentNullException ("actionIfA");
if (tag == TypeTag.A)
{
actionIfA (AValue);
}
}
public void Run (Action<B> actionIfB)
{
if (actionIfB == null)
throw new ArgumentNullException ("actionIfB");
if (tag == TypeTag.B) {
actionIfB (BValue);
}
}
public override string ToString()
{
if (tag == TypeTag.A)
{
return "Type A" + typeof(A).ToString() + ": " + AValue.ToString();
}
else if (tag == TypeTag.B) {
return "Type B" + typeof(B).ToString() + ": " + BValue.ToString();
}
throw new InvalidOperationException ("Unreachable code.");
}
public override int GetHashCode()
{
unchecked
{
int result = tag.GetHashCode();
if (tag == TypeTag.A) {
result = (result * 397)^(AValue != null ? AValue.GetHashCode() : 0);
} else if (tag == TypeTag.B) {
result = (result * 397)^(BValue != null ? BValue.GetHashCode() : 0);
}
return result;
}
}
public override bool Equals (object other)
{
if (other is Union<A,B>)
{
return this.Equals((Union<A,B>)other);
}
return false;
}
public bool Equals (Union<A,B> other)
{
if (this.tag != other.tag)
{
return false;
}
if (tag == TypeTag.A)
{
return this.AValue.Equals(other.AValue);
}
else if (tag == TypeTag.B)
{
return this.AValue.Equals(other.AValue);
}
return false;
}
}
Пример использования:
var i = Union<int,string>.CreateA(5);
var s = Union<int,string>.CreateB("Fre");
s.Run(actionIfA: n => { Console.WriteLine("1.number*3 is " + n*3); },
actionIfB: str => { Console.WriteLine("1.uppercase string is " + str.ToUpper()); });
var r = i.SelectOn(withA: n => "2.number*3 is" + n*3 , withB: str=> "2.uppercase string is" + str.ToUpper());
Console.WriteLine(r);
s.Run(actionIfA: n => { Console.WriteLine("3. number*3 is " + n*3); });
s.Run(actionIfB: str => { Console.WriteLine("4. uppercase string is " + str.ToUpper()); });
i.Run(actionIfA: n => { Console.WriteLine("5. number*3 is " + n*3); });
Console.WriteLine("does i equals s:" + i.Equals(s));
, если вы хотите использовать его в более повелительном/чуть быстрее/менее безопасный способ сделать тег и ценности общественности (или сделать тег общественности и использовать Get (A/B/C/D/E) OrThrow, чтобы использовать лучшие исключения, если вы используете неправильный способ) и используйте if/else или включите его, чтобы использовать AValue/BValue (/ CValue/DValue/EValue, если вы используете 3/4/5 кортежа). Обратите внимание, что это делает невозможным заставить вас обрабатывать все состояния и делает его более вероятным, если вы испортите и используете неправильный тип.
Как он отличается от 'Tuple' или 'Tuple '? Пример использования может прояснить вашу цель ... –
Не могли бы вы быть более ясными о том, чего вы хотите достичь? Я не понимаю причину этого намеченного дизайна. – PMF
Возможно, словарь - это то, что вы ищете. –