C# - 任何类似于boost :: any的东西?

时间:2012-02-23 11:51:54

标签: c# generics boost-any

我有一个要求: 1.我需要在列表中存储任何类型的对象 2.避免尽可能地打电话

为此,我试图想出一些东西。无论我尝试什么,我都无法摆脱拳击\拆箱。我想知道你们中是否有人遇到过能够实现这一目标的事情。

我创建的类几乎没用,除非你处理小集合,因为在内存和性能方面它需要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:是的,简而言之: List GenericGenericCollection = new List();
GenericGenericCollection.Add(new string(“a sonnet”);
GenericGenericCollection.Add(42);
GenericGenericCollection.Add(new MyOwnCustomType);

再次编辑

我找到了两种方法: 1.在.NET 4中,引入了一个新的“动态”关键字。如果您将行Object _o;替换为dynamic _o;,则可以按原样使用代码。问题是虽然动态应该是动态类型,但性能就像拳击..

  1. 通过添加隐式(我更喜欢)或显式强制转换运算符而不是依赖泛型==运算符,可以提高性能。

  2. 基于http://igoro.com/archive/fun-with-c-generics-down-casting-to-a-generic-type/我添加了以下课程。这样可以解决装箱和性能问题 - 下面的类性能比int或Castable的ArrayList要好一些。当然,List<int>比较时还有很长的路要走。 从我的观点来看,唯一的问题是,一旦将对象分配给plain Any对象以获得嵌入AnyInternal<T>内的具体类型。我都找不到方法T Get()。甚至关键字动态在运行时在语句中失败:

  3. 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;
            }
        }
    }
    

1 个答案:

答案 0 :(得分:1)

使用通用列表&lt; T&gt; (在System.Collections.Generic中)而不是ArrayList 对于值类型,不会发生任何装箱/拆箱。