2012-02-23 18 views
0

我有哪裏的要求:1。 我需要存儲在列表中的任何類型的對象 2.避免鑄造呼籲儘可能C# - 任何類似於boost :: any的東西?

爲此我試圖來的東西。無論我嘗試過什麼,我都無法擺脫拳擊\拆箱。我想知道你們中是否有人遇到過能夠實現這一目標的事情。

我創建的類幾乎沒有用處,除非您處理的是小集合,因爲在內存和性能方面它需要1.5倍ArrayList。我試圖找到改善其中至少一個的方法(最好是性能)。

任何反饋意見。

public class Castable 
    { 
     Object _o; 

     public override bool Equals(object obj) { return base.Equals(obj); } 

     public override int GetHashCode() { return base.GetHashCode(); } 

     public bool Equals<T>(T obj) 
     { 
      T v1 = (T)this._o; 
      //T v2 = obj; 
      //var v2 = obj; // Convert.ChangeType(obj, obj.GetType()); 

      // This doesn't work.. (Cannot convert T to Castable 
      //var v2 = Convert.ChangeType(this.GetType() == obj.GetType() ? 
      //((Castable)obj)._o.GetType(), obj.GetType()); 

      //if (((T)this._o) != obj) //<== why this doesn't work? 
      //if (v1 == obj) //<== "Operator '==' cannot be applied to operands of type 'T' and 'T'" 
      if(v1.Equals(obj)) 
      { 
       return true; 
      } 

      return false; 
     } 

     public bool Equals(Castable obj) 
     { 
      var v = Convert.ChangeType(obj._o, obj._o.GetType()); 
      return Equals(v); 
     } 


     public static bool operator ==(Castable a, Castable b) 
     { 
      return a.Equals(b); 
     } 

     public static bool operator !=(Castable a, Castable b) 
     { 
      return !a.Equals(b); 
     } 

     #region HOW CAN WE USE GENRIC TYPE FOR == and != OPERATOR? 
     public static bool operator ==(Castable a, object b) 
     { 
      return a.Equals(b); 
     } 

     public static bool operator !=(Castable a, object b) 
     { 
      return !a.Equals(b); 
     } 
     #endregion 

     public void Set<T>(T t) { _o = t; } 

     public T Get<T>() { return (T)_o; } 

     public static long TestLookup(IList list, int elements, int lookups) 
     { 
      object value; 
      Stopwatch watch = new Stopwatch(); 
      watch.Start(); 
      for (long index = 0; index < lookups; ++index) 
      { 
       value = list[random.Next(0, elements - 1)]; 
      } 
      watch.Stop(); 

      return watch.ElapsedMilliseconds; 
     } 

     public static long TestCompare(IList list, int elements, int lookups) 
     { 
      //object value; 
      bool match; 
      Stopwatch watch = new Stopwatch(); 
      watch.Start(); 
      for (long index = 0; index < lookups; ++index) 
      { 
       match = random.Next() == (int)list[random.Next(0, elements - 1)]; 
      } 
      watch.Stop(); 

      return watch.ElapsedMilliseconds; 
     } 

     public static long TestCompareCastable(IList<Castable> list, int elements, int lookups) 
     { 
      //object value; 
      bool match; 
      Stopwatch watch = new Stopwatch(); 
      watch.Start(); 
      for (long index = 0; index < lookups; ++index) 
      { 
       match = list[random.Next(0, elements - 1)] == random.Next(); //most of the times 1.4 times 
       //match = list[random.Next(0, elements - 1)].Equals(random.Next()); // may be 1.3 times ArrayList 
      } 
      watch.Stop(); 

      return watch.ElapsedMilliseconds; 
     } 


     public static void Test(int elements, int lookups, int times) 
     { 
      List<int> intList = new List<int>(); 
      List<Castable> castableList = new List<Castable>(); 
      ArrayList intArrayList = new ArrayList(); 

      if (Stopwatch.IsHighResolution) 
       Console.WriteLine("We have a high resolution timer available"); 

      long frequency = Stopwatch.Frequency; 
      Console.WriteLine(" Timer frequency in ticks per second = {0}", frequency); 

      for (int index = 0; index < elements; ++index) 
      { 
       intList.Add(random.Next()); 
       intArrayList.Add(random.Next()); 
       Castable c = new Castable(); 
       c.Set(random.Next()); 
       castableList.Add(c); 
      } 

      long ms = 0; 


      string result = ""; 
      string ratios = ""; 
      for (int time = 0; time < times; ++time) 
      { 
       ms = TestLookup(intList, elements, lookups); 
       result += "intList Lookup Time " + ms.ToString() + " MS\n"; 
       ms = TestLookup(castableList, elements, lookups); 
       result += "intArrayList Lookup Time " + ms.ToString() + " MS\n"; 
       ms = TestLookup(intArrayList, elements, lookups); 
       result += "castableList Lookup Time " + ms.ToString() + " MS\n"; 

       ms = TestCompare(intList, elements, lookups); 
       result += "intList Compare Time " + ms.ToString() + " MS\n"; 
       long msarraylist = ms = TestCompare(intArrayList, elements, lookups); 
       result += "intArrayList Compare Time " + ms.ToString() + " MS\n"; 
       ms = TestCompareCastable(castableList, elements, lookups); 
       result += "castableList Compare Time " + ms.ToString() + " MS\n"; 
       ratios += String.Format("round: {0}, ratio: {1}\n", time, (float)ms/msarraylist); 
      } 

      //MessageBox.Show(result); 
      MessageBox.Show(ratios); 


      int i = 10; 
      Castable o1 = new Castable(); 
      o1.Set(i); 
      int j = 10; 
      Castable o2 = new Castable(); 
      o2.Set(j); 
      if (!o1.Equals(10)) 
      { 
       Console.WriteLine("unequal"); 
      } 

      if (!o1.Equals(o2)) 
      { 
       Console.WriteLine("unequal"); 
      } 

      if (o1 != j) 
      { 
       Console.WriteLine("unequal"); 
      } 

      int x = o1.Get<int>(); 

     } 

    } 

編輯

總之我想實現:

@ winSharp93:是的,在短: 列表GenericGenericCollection =新名單();
GenericGenericCollection.Add(新字符串( 「十四行詩」);
GenericGenericCollection.Add(42);
GenericGenericCollection.Add(新MyOwnCustomType);

再次編輯

有兩種我發現的方法: 1.在.NET 4中引入了一個新的'dynamic'關鍵字,如果用dynamic _o;代替行Object _o;,您可以照原樣使用代碼。問題是雖然動態應該是動態的類型,性能就像拳擊..

  1. 性能可以通過添加隱式的(我喜歡)或顯式轉換操作符,而不是依賴於通用的==操作符來提高。

  2. 根據http://igoro.com/archive/fun-with-c-generics-down-casting-to-a-generic-type/我添加了以下類。這需要關心拳擊和性能 - 下面的類的性能比int或Castable的ArrayList好一點。當然,當List<int>比較時,它還有很長的路要走。 從我的角度來看,唯一的問題是,一旦將對象分配給普通Any對象以獲取嵌入在AnyInternal<T>內部的具體類型。我也無法找到方法T Get()。即使關鍵字的動態在運行時出現故障,在statment:

Any.AnyInternal<dynamic> any = (Any.AnyInternal<dynamic>)anyInstanceContainingAnyInternalForInt;

//too bad I can't seal Any after AnyInternal<T> has derived from it. 
public abstract class Any 
{ 
    public static implicit operator int(Any any) 
    { 
     return Any.ToType<int>(any).Data; 
    } 

    public static AnyInternal<T> ToType<T>(Any any) 
    { 
     return ((AnyInternal<T>)any); 
    } 

    public class AnyInternal<T> : Any 
    { 
     private T _data; 
     public T Data { get { return _data; } } 
     public AnyInternal(T data) 
     { 
      _data = data; 
     } 
    } 
} 
+0

你爲什麼不把你的類型聲明爲Castable ,並將_o聲明爲T類型? – 2012-02-23 11:56:46

+0

因爲它將Castable綁定到T,我想要一個列表,其中Castable沒有綁定到類型。 – 2012-02-23 12:03:06

+0

我會退後一步,看看手頭的問題。如果集合中的拳擊對你來說是一個問題,我會考慮實現我自己的集合,它內部擁有多個內部集合。一個用於已知的值類型,另一個用於對象。創建Add方法的重載將允許您將正確的項目放在正確的內部集合中 – Polity 2012-02-23 12:09:09

回答

1

使用泛型列表<牛逼>(內System.Collections.Generic),而不是ArrayList的。
對於值類型不會發生任何裝箱/拆箱操作。

+0

相同的答案作爲上面的全李歡 – 2012-02-23 12:04:15

+0

所以你想存儲多個值類型(但沒有類)在一個列表中沒有拳擊? – Matthias 2012-02-23 12:05:18

+0

是,簡而言之: 列表 GenericGenericCollection =新列表(); (新的字符串(「一個sonnet」); GenericGenericCollection.Add(42); GenericGenericCollection.Add(new MyOwnCustomType); – 2012-02-23 12:09:02

相關問題