Dear200892 2022-02-21 10:02 采纳率: 50%
浏览 36
已结题

自定义字典类排序时遇到未将对象引用到实例

问题遇到的现象

我想以多线程的办法去处理表格里的数据,并在其方法内部进行业务操作,于是我自定义了一个字典类MyDictionary。
但我想要给进行排序操作的时候,程序报错"未将对象引用到实例",总数量Count没有变化,但item都是对象的默认值。
我是漏掉了什么步骤了吗?

运行结果及报错内容

img

问题相关代码
public class MyDictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable
    {
        /// <summary>
        /// 数据源
        /// </summary>
        private ConcurrentDictionary<TKey, TValue> _items;

        public MyDictionary()
        {
                _items = new ConcurrentDictionary<TKey, TValue>();
        }

        /// <summary>
        /// 获取或设置具有指定键的元素
        /// </summary>
        /// <param name="key">要获取或设置的元素的键</param>
        /// <returns></returns>
        public TValue this[TKey key]
        {
            get
            {
                return _items[key];
            }
            set
            {
                if (_items.ContainsKey(key))
                    _items[key] = value;
                else
                    Add(key, value);
            }
        }

        /// <summary>
        /// 获取或设置具有指定键的元素
        /// </summary>
        /// <param name="key">要获取或设置的元素的键</param>
        /// <returns></returns>
        public object this[object key] { get { return ((IDictionary)_items)[key]; } set { ((IDictionary)_items)[key] = value; } }

        /// <summary>
        /// 获得一个包含字典中的键的集合
        /// </summary>
        public ICollection<TKey> Keys { get { return _items.Keys; } }

        /// <summary>
        /// 获得一个包含字典中的键的集合
        /// </summary>
        ICollection IDictionary.Keys { get { return ((IDictionary)_items).Keys; } }

        /// <summary>
        /// 获得一个包含字典中的值的集合
        /// </summary>
        public ICollection<TValue> Values { get { return _items.Values; } }

        /// <summary>
        /// 获得一个包含字典中的值的集合
        /// </summary>
        ICollection IDictionary.Values { get { return ((IDictionary)_items).Values; } }

        /// <summary>
        /// 获取包含在字典中的键/值对的数目
        /// </summary>
        public int Count { get { return _items.Count(); } }

        /// <summary>
        /// 获取一个值,该值指示<see cref="ICollection"/>是否为只读
        /// </summary>
        public bool IsReadOnly { get { return false; } }

        private object _syncRoot;
        /// <summary>
        /// 获取可用于同步对<see cref="ArrayList"/>的访问的对象
        /// </summary>
        public object SyncRoot
        {
            get
            {
                if (_syncRoot == null)
                    Interlocked.CompareExchange(ref this._syncRoot, new object(), null);
                return _syncRoot;
            }
        }

        /// <summary>
        /// 获取一个值,该值指示是否同步对<see cref="ArrayList"/>的访问(线程安全)
        /// </summary>
        public bool IsSynchronized { get { return true; } }

        /// <summary>
        /// 获取一个值,该值指示是否<see cref="ICollection"/>对象具有固定的大小
        /// </summary>
        public bool IsFixedSize { get { return false; } }        

        /// <summary>
        /// 将指定的键和值添加到字典中
        /// </summary>
        /// <param name="key">要添加的元素的键</param>
        /// <param name="value">要添加的元素的值。对于引用类型,该值可以为 null</param>
        public void Add(TKey key, TValue value)
        {
            if (!_items.TryAdd(key, value))
                throw new ArgumentException("字典中已存在具有相同键的元素");
        }

        /// <summary>
        /// 将指定的键和值添加到字典中
        /// </summary>
        /// <param name="item">要添加键/值对</param>
        public void Add(KeyValuePair<TKey, TValue> item)
        {
            Add(item.Key, item.Value);
        }

        /// <summary>
        /// 将指定的键和值添加到字典中
        /// </summary>
        /// <param name="key">要添加的元素的键</param>
        /// <param name="value">要添加的元素的值。对于引用类型,该值可以为 null</param>
        void IDictionary.Add(object key, object value)
        {
            TKey _key = ConvertKey(key);
            ((IDictionary)_items).Add(_key, (int)value);
        }

        /// <summary>
        /// 将所有元素从字典中移除
        /// </summary>
        public void Clear()
        {
            _items.Clear();
        }

        /// <summary>
        /// 确定是否字典中包含指定键
        /// </summary>
        /// <param name="key">定位的键</param>
        /// <returns></returns>
        public bool ContainsKey(TKey key)
        {
            return _items.ContainsKey(key);
        }

        /// <summary>
        /// 确定是否字典中包含指定键
        /// </summary>
        /// <param name="item">定位的键/值对</param>
        /// <returns></returns>
        public bool Contains(KeyValuePair<TKey, TValue> item)
        {
            return _items.Contains<KeyValuePair<TKey, TValue>>(item);
        }

        /// <summary>
        /// 确定是否字典中包含指定键
        /// </summary>
        /// <param name="key">定位的键</param>
        /// <returns></returns>
        public bool Contains(object key)
        {
            TKey _key = ConvertKey(key);
            return _items.ContainsKey(_key);
        }

        /// <summary>
        ///  从第一个元素开始复制<see cref="Array"/>中的一系列元素,将它们粘贴到另一<see cref="Array"/>中(从第一个元素开始)
        /// </summary>
        /// <param name="array">接收数据的<see cref="Array"/></param>
        /// <param name="index">一个 32 位整数,它表示要复制的元素数目</param>
        public void CopyTo(Array array, int index)
        {
            if (index < 0)
                throw new ArgumentOutOfRangeException("index小于零");

            if (index > array.Length)
                throw new ArgumentException("index大于字典中的元素数");

            if (index > array.Length || array == null)
                throw new ArgumentNullException("未将对象引用到实例");

            Array.Copy(_items.ToArray(), array, index);
        }

        /// <summary>
        ///  从第一个元素开始复制<see cref="Array"/>中的一系列元素,将它们粘贴到另一<see cref="Array"/>中(从第一个元素开始)
        /// </summary>
        /// <param name="array">接收数据的<see cref="Array"/></param>
        /// <param name="arrayIndex">一个 32 位整数,它表示要复制的元素数目</param>
        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
        {
            Array.Copy(_items.ToArray(), array, arrayIndex);
        }

        /// <summary>
        /// 将带有指定键的值从字典中移除
        /// </summary>
        /// <param name="key">要移除的元素的键</param>
        /// <returns></returns>
        public bool Remove(TKey key)
        {
            TValue outValue = default(TValue);
            return _items.TryRemove(key, out outValue);
        }

        /// <summary>
        /// 将带有指定键/值对从字典中移除
        /// </summary>
        /// <param name="key">要移除的键/值对</param>
        /// <returns></returns>
        public bool Remove(KeyValuePair<TKey, TValue> item)
        {
            return Remove(item.Key);
        }

        /// <summary>
        /// 将带有指定键的值从字典中移除
        /// </summary>
        /// <param name="key">要移除的元素的键</param>
        /// <returns></returns>
        void IDictionary.Remove(object key)
        {
            TKey _key = ConvertKey(key);
            ((IDictionary)_items).Remove(_key);
        }

        /// <summary>
        /// 尝试从字典中获取与指定的键关联的值
        /// </summary>
        /// <param name="key">要获取的值的键</param>
        /// <param name="value">当此方法返回时,将包含字典中具有指定键的对象;如果操作失败,则包含类型的默认值</param>
        /// <returns></returns>
        public bool TryGetValue(TKey key, out TValue value)
        {
            return _items.TryGetValue(key, out value);
        }

        /// <summary>
        /// 返回一个循环访问集合的枚举器
        /// </summary>
        /// <returns></returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return new Enumerator(this, Enumerator.KeyValuePair);
        }

        /// <summary>
        /// 返回一个循环访问集合的枚举器
        /// </summary>
        /// <returns></returns>
        IDictionaryEnumerator IDictionary.GetEnumerator()
        {
            return new Enumerator(this, Enumerator.DictEntry);
        }

        /// <summary>
        /// 将<see cref="object"/>转换为<see cref="TKey"/>
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        private TKey ConvertKey(object key)
        {
            TKey _key = key as TKey;
            if (key == null)
                throw new InvalidCastException("key不是有效类型");
            return _key;
        }

        Enumerator GetEnumerator()
        {
            return new Enumerator(this, Enumerator.KeyValuePair);
        }

        IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
        {
            return new Enumerator(this, Enumerator.KeyValuePair);
        }

        private struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>, IDictionaryEnumerator
        {
            private Dictionary<TKey, TValue> dictionary;

            private KeyValuePair<TKey, TValue> current;

            private int index;

            private int getEnumeratorRetType;  // What should Enumerator.Current return?

            internal const int DictEntry = 1;
            internal const int KeyValuePair = 2;

            public Enumerator(MyDictionary<TKey, TValue> source, int _getEnumeratorRetType)
            {
                dictionary = new Dictionary<TKey, TValue>((IDictionary<TKey, TValue>)source._items);
                index = 0;
                getEnumeratorRetType = _getEnumeratorRetType;
                current = new KeyValuePair<TKey, TValue>();
            }

            public KeyValuePair<TKey, TValue> Current { get { return current; } }

            object IEnumerator.Current
            {
                get
                {
                    if (getEnumeratorRetType == DictEntry)
                        return new DictionaryEntry(current.Key, current.Value);
                    else
                        return new KeyValuePair<TKey, TValue>(current.Key, current.Value);
                }
            }

            object IDictionaryEnumerator.Key { get { return current.Key; } }

            object IDictionaryEnumerator.Value { get { return current.Value; } }

            DictionaryEntry IDictionaryEnumerator.Entry
            {
                get
                {
                    return new DictionaryEntry(current.Key, current.Value);
                }
            }

            public void Dispose()
            {

            }

            public bool MoveNext()
            {
                while (index < dictionary.Count)
                {
                    current = new KeyValuePair<TKey, TValue>(dictionary.ElementAt(index).Key, dictionary.ElementAt(index).Value);
                    index++;
                    return true;
                }

                index = dictionary.Count + 1;
                current = new KeyValuePair<TKey, TValue>();
                return false;
            }

            void IEnumerator.Reset()
            {
                index = 0;
                current = new KeyValuePair<TKey, TValue>();
            }
        }
    }

  • 写回答

5条回答 默认 最新

  • Dear200892 2022-02-22 14:51
    关注

    OrderByDescending()会执行到自定义字典类的CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)方法
    旧代码里,我是直接调用了Array.Copy()。
    利用Dnspy反编译了System.Core.dll内容,在Buffer(IEnumerable<TElement> source)内有这么一段
    collection.CopyTo(array, 0);
    第二个参数为0,自定义类的CopyTo第二个参数arrayIndex=>0。导致Array.Copy()既不报错,也没有复制数据。
    按照微软给出的源码,我把CopyTo更改了

            /// <summary>
            ///  从第一个元素开始复制<see cref="Array"/>中的一系列元素,将它们粘贴到另一<see cref="Array"/>中(从第一个元素开始)
            /// </summary>
            /// <param name="array">接收数据的<see cref="Array"/></param>
            /// <param name="arrayIndex">一个 32 位整数,它表示要复制的元素数目</param>
            public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
            {
                if (array == null)
                    throw new ArgumentNullException("array不能为空");
    
                if (arrayIndex ! = 0)
                    throw new ArgumentException("arrayIndex需要等于0");
    
                foreach (var item in _items)
                {
                    array[arrayIndex++] = item;
                }
            }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(4条)

报告相同问题?

问题事件

  • 系统已结题 3月2日
  • 已采纳回答 2月22日
  • 修改了问题 2月21日
  • 创建了问题 2月21日

悬赏问题

  • ¥15 UE5 如何可以不渲染HDRIBackdrop背景
  • ¥70 2048小游戏毕设项目
  • ¥20 mysql架构,按照姓名分表
  • ¥15 MATLAB实现区间[a,b]上的Gauss-Legendre积分
  • ¥15 Macbookpro 连接热点正常上网,连接不了Wi-Fi。
  • ¥15 delphi webbrowser组件网页下拉菜单自动选择问题
  • ¥15 linux驱动,linux应用,多线程
  • ¥20 我要一个分身加定位两个功能的安卓app
  • ¥15 基于FOC驱动器,如何实现卡丁车下坡无阻力的遛坡的效果
  • ¥15 IAR程序莫名变量多重定义