2014-01-31 57 views
0

我有一個數據庫,可以將字符串和整數保存爲值。 當我通過數據庫時,我想添加每個數據插槽與數據庫中的內容。enum中的泛型

我決定做一個收集器類,它可以接受int或字符串,我想創建這樣一個枚舉:

HAXE代碼:

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

例如A可以是int和B - 字符串。

這是可能在C#中做什麼或者什麼樣的模擬此功能的最佳方法:保持強類型(無動態變量)以進行編譯器類型檢查。

編輯

我不能使用元組,因爲它在Unity3D

+0

它與「元組」或「元組」有什麼不同?示例的使用可能會澄清你的目標... –

+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

注意這個人似乎並沒有要求一個Tuple(一種持有c類型struct但沒有名字的幾種類型的類型),而是一個Tagged Union/Sum type

一個元組有一種類型,一個帶標籤的聯合只有一個值爲2或更多的類型。

他給出的例子是一個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元組)。請注意,這使得你不可能強迫你處理所有的狀態,並且使你更容易混淆並使用錯誤的類型。