Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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)

private IDictionary<Type, IEnumerable<T>> _dataOfType where T: BaseClass; //does not compile! 

The concrete classes I want to store, all derive from BaseClass, therefore the idea to use it as constraint. The compiler complains that it expects a semicolon after the member name.

If it would work, I would expect this would make the later retrieval from the dictionary simple like:

IEnumerable<ConcreteData> concreteData; _sitesOfType.TryGetValue(typeof(ConcreteType), out concreteData); 

How to define such a dictionary?

like image 675
Marcel Avatar asked May 31 '10 14:05

Marcel


People also ask

What does |= mean in C?

The ' |= ' symbol is the bitwise OR assignment operator.

What is '~' in C programming?

In mathematics, the tilde often represents approximation, especially when used in duplicate, and is sometimes called the "equivalency sign." In regular expressions, the tilde is used as an operator in pattern matching, and in C programming, it is used as a bitwise operator representing a unary negation (i.e., "bitwise ...

What is operators in C?

C operators are one of the features in C which has symbols that can be used to perform mathematical, relational, bitwise, conditional, or logical manipulations. The C programming language has a lot of built-in operators to perform various tasks as per the need of the program.


2 Answers

Use System.ComponentModel.Design.ServiceContainer that is already available in .Net framework.

        ServiceContainer container = new ServiceContainer();          IList<int> integers = new List<int>();         IList<string> strings = new List<string>();         IList<double> doubles = new List<double>();          container.AddService(typeof(IEnumerable<int>), integers);         container.AddService(typeof(IEnumerable<string>), strings);         container.AddService(typeof(IEnumerable<double>), doubles); 
like image 165
this. __curious_geek Avatar answered Oct 09 '22 05:10

this. __curious_geek


You may not even need a dictionary to be able to do this - but that depends on your needs. If you only ever need 1 such list per type per appdomain (i.e. the "dictionary" is static), the following pattern can be efficient and promotes type-inference nicely:

interface IBase {}  static class Container {     static class PerType<T> where T : IBase {         public static IEnumerable<T> list;     }      public static IEnumerable<T> Get<T>() where T : IBase          => PerType<T>.list;       public static void Set<T>(IEnumerable<T> newlist) where T : IBase          => PerType<T>.list = newlist;      public static IEnumerable<T> GetByExample<T>(T ignoredExample) where T : IBase          => Get<T>();  } 

Note that you should think carefully before adopting this approach about the distinction between compile-time type and run-time type. This method will happily let you store a runtime-typed IEnumerable<SomeType> variable both under SomeType and -if you cast it- under any of SomeType's base types, including IBase, with neither a runtime nor compiletype error - which might be a feature, or a bug waiting to happen, so you may want an if to check that.

Additionally, this approach ignores threading; so if you want to access this data-structure from multiple threads, you probably want to add some locking. Reference read/writes are atomic, so you're not going to get corruption if you fail to lock, but stale data and race conditions are certainly possible.

like image 35
Eamon Nerbonne Avatar answered Oct 09 '22 04:10

Eamon Nerbonne