2014-01-31 2 views
0

У меня есть база данных, которая может содержать строки и целые числа в качестве значений. Когда я иду через базу данных, я хочу добавить каждый слот данных с содержимым из БД.Generics in enum

Я решил сделать класс коллектора, который может принимать либо INT или строку, и я хотел бы создать перечисление вроде этого:

Haxe код:

enum Either<A,B> 
{ 
    Left(v:A); 
    Right(v:B); 
} 

Например A может быть int и B - string.

Возможно ли это сделать на C# или что было бы лучшим подходом для имитации этой функции: сохранение сильных типов (без динамических переменных) для проверки типа компилятора.

EDIT:

Я не могу использовать Tuple, так как он не имеет поддержки в Unity3D

+0

Как он отличается от 'Tuple ' или 'Tuple '? Пример использования может прояснить вашу цель ... –

+0

Не могли бы вы быть более ясными о том, чего вы хотите достичь? Я не понимаю причину этого намеченного дизайна. – PMF

+0

Возможно, словарь - это то, что вы ищете. –

ответ

0

Невозможно иметь общий перечисление таким образом, как вы описали. Но что не удается создать вашу собственную реализацию Tuple?

public class Tuple<TLeft, TRight> { 
    public TLeft Left { get; set; } 
    public TRight Right { get; set; } 
} 

Если вам нужна поддержка сериализации, которая довольно часто требовали в Unity3D, украсить свой класс с SerializableAttibute. Все, что в ваших руках, для исследования внутренних компонентов родного .NET Tuple и копирования некоторых полезных частей.

0

Перечисление является в основном просто набор констант. Каждая константа имеет идентификатор, который должен быть дружественным именем, которое можно использовать в коде, а числовое значение используется под капотом. Таким образом, ответ на ваш вопрос «нет».

При этом, если у вас есть значение перечисления, вы можете вызвать его метод ToString, чтобы преобразовать его в строку, содержащую имя идентификатора. Я думаю, что вы также можете использовать его как int или любой другой тип, указанный в объявлении типа. Класс Enum также имеет статические методы, которые преобразуют другой способ и многое другое.

0

Обратите внимание, что человек, похоже, не запрашивает кортеж (тип, который содержит несколько типов, таких как структура стиля 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 кортежа). Обратите внимание, что это делает невозможным заставить вас обрабатывать все состояния и делает его более вероятным, если вы испортите и используете неправильный тип.