In C#: How to declare a generic Dictionary with a type as key and an IEnumerable<> of that type as value?

后端 未结 6 1236
我在风中等你
我在风中等你 2020-12-24 12:10

I want to declare a dictionary that stores typed IEnumerable\'s of a specific type, with that exact type as key, like so: (Edited to follow johny g\'s comment)<

6条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2020-12-24 12:36

    1. You can't constrain a specific variable. It only works on classes and methods. It really doesn't make any sense in the variable level, to be honest.
    2. What you want is a custom class - class WeirdDictionary : IDictionary, that will overload the Add method to take a Type and an IEnumerable of that type, which you can do using constraints, and cast the IEnumerable<> to IEnumerable. Overload the indexer aswell, and cast it back to the relevant type.
      All this casting is needed, since generics are strict about IEnumerable being as good as IEnumerable (This is called variance, I believe?)

    This solution is slightly generalized, since reuse rocks

    Edit by 280Z28:

    At first I marked this down because point #2 was confusing and I misinterpreted it. By using explicit implementation of methods in IDictionary and providing generic alternatives, you can get a pretty clean interface. Note that you cannot create generic indexers, so you'll have to always use TryGet (which is a good idea anyway). I only included explicit implementation of one of the IDictionary<> methods to show how to perform the checks. Do not derive WeirdDictionary directly from Dictionary or you will lose the ability to guarantee constraints in the underlying data.

    class WeirdDictionary : IDictionary
    {
        private readonly Dictionary _data =
            new Dictionary();
    
        public void Add(IEnumerable value)
        {
            _data.Add(typeof(T), value);
        }
    
        public bool TryGet(out IEnumerable value)
        {
            IEnumerable enumerable;
            if (_data.TryGetValue(typeof(T), out enumerable)
            {
                value = (IEnumerable)enumerable;
                return true;
            }
    
            value = null;
            return false;
        }
    
        // use explicit implementation to discourage use of this method since
        // the manual type checking is much slower that the generic version above
        void IDictionary.Add(Type key, IEnumerable value)
        {
            if (key == null)
                throw new ArgumentNullException("key");
            if (value != null && !typeof(IEnumerable<>).MakeGenericType(key).IsAssignableFrom(value.GetType()))
                throw new ArgumentException(string.Format("'value' does not implement IEnumerable<{0}>", key));
    
            _data.Add(key, value);
        }
    }
    

    End 280Z28

提交回复
热议问题