代码之家  ›  专栏  ›  技术社区  ›  Kevin Kibler

是否有KeyedCollection的一般具体实现?

  •  13
  • Kevin Kibler  · 技术社区  · 15 年前

    这个 System.Collections.ObjectModel.KeyedCollection System.Collections.Generic.Dictionary ,尤其是当关键数据是存储对象的一部分或希望能够按顺序枚举项时。不幸的是,这个类是抽象的,我无法在核心.NET框架中找到一个通用的具体实现。

    Framework Design Guidlines 书中指出了一个具体的实现 应该 为抽象类型提供(第4.4节抽象类设计)。为什么框架设计者会忽略这样一个有用类的一般具体实现,特别是当它可以通过简单地公开一个接受和存储 Converter 从项目到其键:

    public class ConcreteKeyedCollection<TKey, TItem> : KeyedCollection<TKey, TItem>
    {
        private Converter<TItem, TKey> getKeyForItem = null;
        public ConcreteKeyedCollection(Converter<TItem, TKey> getKeyForItem)
        {
            if (getKeyForItem == null) { throw new ArgumentNullException("getKeyForItem"); }
            this.getKeyForItem = getKeyForItem;
        }
        protected override TKey GetKeyForItem(TItem item)
        {
            return this.getKeyForItem(item);
        }
    }
    
    4 回复  |  直到 14 年前
        1
  •  9
  •   user7116    15 年前

    根据你问题的精神,没有通用的实现,因为我不为微软工作,所以我只能推测。因为具体的实现正如您所展示的那样简单,所以我不会提供任何推测(因为这可能是错误的)。

        2
  •  3
  •   Ohad Schneider    10 年前

    这是我提出的实现

    public class LookupKeyedCollection<TKey, TItem> : KeyedCollection<TKey, TItem>
    {
        private Func<TItem, TKey> _getKeyFunc;
    
        public LookupKeyedCollection(Func<TItem, TKey> getKeyFunc)
        {
            _getKeyFunc = getKeyFunc;
        }
    
        //Required KeyedCollection implementation
        protected override TKey GetKeyForItem(TItem item)
        {
            return _getKeyFunc(item);
        }
    
        public bool TryGetItem(TKey key, out TItem item)
        {
            if (Dictionary == null)
            {
                item = default(TItem);
                return false;
            }
    
            return Dictionary.TryGetValue(key, out item);
        }
    
        public void AddOrUpdate(TItem item)
        {
        Remove(_getKeyFunc(item));
        Add(item);
        }
    
        public new bool Contains(TItem item)
        {
            return base.Contains(_getKeyFunc(item));
        }
    }
    

        3
  •  1
  •   Eli Arbel    10 年前

    没有具体实现的原因是它不可序列化(不能序列化委托)。BCL中的所有集合都可以序列化。

        4
  •  0
  •   Bryan Legend    12 年前

    这是我想出的一个。它可以硬编码属性名称,也可以根据需要使用[Key]属性。

        ///// <summary>
    ///// Creates an indexed list.  Requires that [Key] attribute be applied to a property in TValue object.
    ///// </summary>
    ///// <example>
    ///// public class Test
    ///// {
    /////     [Key]
    /////     public int Id { get; set; }
    ///// }
    ///// 
    ///// IndexedList<int, Test> tests;
    ///// </example>
    ///// <typeparam name="TKey"></typeparam>
    ///// <typeparam name="TValue"></typeparam>
    public class IndexedList<TKey, TValue> : KeyedCollection<TKey, TValue>
    {
        PropertyInfo keyProperty;
    
        public IndexedList()
        {
            foreach (var property in typeof(TValue).GetProperties())
            {
                // this requires .net 4, which I couldn't use due to the WPF shadow effect deprication
                //if (property.PropertyType == typeof(TKey) && property.IsDefined(typeof(KeyAttribute), true))
    
                if (property.PropertyType == typeof(TKey) && (property.Name.ToUpper() == "ID" || property.Name.ToUpper() == "KEY"))
                {
                    keyProperty = property;
                    return;
                }
            }
    
            throw new ArgumentException(String.Format("Unable to find a property in {0} that is named Id or Key and is of type {1}.", typeof(TValue).Name, typeof(TKey).Name));
        }
    
        protected override TKey GetKeyForItem(TValue item)
        {
            return (TKey)keyProperty.GetValue(item, null);
        }
    }