I have a generic dictionary that pass to a method which only accepts IQueryable as a parameter
Is it possible to cast the queryable back to the original dictionary? And I don't mean creating a new dictionary with .ToDictionary(...)
private static void Main()
{
var dict = new Dictionary<int, int>();
dict.Add(1,1);
SomeMethod(dict.AsQueryable());
}
public static void SomeMethod(IQueryable dataSource)
{
// dataSource as Dictionary<int, int> --> null
var dict = dataSource.???
}
I know in this simple example this does not make much sense. But in the big picture I have an interface which requires me to return an IQueryable as a dataSource. On implementation returns a dictionary. On a different place in my code I have classes that process the dataSources.
The processor knows that the dataSource will be an Dictionary but I don't want to have the overhead for creating another Dictionary if I already have one.
The .AsQueryable() extension method returns an instance of the EnumerableQuery<T> wrapper class if it is called on something that was not already an IQueryable<T>.
This wrapper class has an .Enumerable property with internal access that provides access to the original object that .AsQueryable() was called on. So you could do this to get back your original dictionary:
var dict = new Dictionary<int, int>();
dict.Add(1,1);
var q = dict.AsQueryable();
Type tInfo = q.GetType();
PropertyInfo pInfo = tInfo.GetProperties(BindingFlags.NonPublic |
BindingFlags.Instance)
.FirstOrDefault(p => p.Name == "Enumerable");
if (pInfo != null)
{
object originalDictionary = pInfo.GetValue(q, null);
Console.WriteLine(dict == originalDictionary); // true
}
However, this is generally a pretty bad idea. internal members have their access restricted for a reason, and I don't think there's any guarantee that the internal implementation of .AsQueryable() won't change at some point in the future. So your best bet is to either find a way to make the original dictionary accessible, or go ahead and make a new one.
One possible workaround (which is not great) is to make your own wrapper class to carry the dictionary along:
private class DictionaryQueryHolder<TKey, TValue> : IQueryable<KeyValuePair<TKey, TValue>>
{
public IDictionary<TKey, TValue> Dictionary { get; private set; }
private IQueryable<KeyValuePair<TKey, TValue>> Queryable { get; set; }
internal DictionaryQueryHolder(IDictionary<TKey, TValue> dictionary)
{
Dictionary = dictionary;
Queryable = dictionary.AsQueryable();
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return Queryable.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public Expression Expression
{
get { return Queryable.Expression; }
}
public Type ElementType
{
get { return Queryable.ElementType; }
}
public IQueryProvider Provider
{
get { return Queryable.Provider; }
}
}
This would both act as a wrapper for the dictionary's IQueryable<T> and provide access to the original dictionary. But on the other hand, anyone trying to retrieve the dictionary would have to know what the generic type parameters were (e.g. <string, string>, <int, string>, etc.) in order to cast it successfully.
The main problem here is that IQueryable wraps itself around the Dictionary rather than being like IEnumerable<> over IDictionary<>, where you could cast it back.
You can certainly find out if the type wrapped is a dictionary if you know the types involved:
public bool isDictionary<T>(object obj) {
return obj.GetType().GenericTypeArguments.Contains(typeof(T));
}
isDictionary<KeyValuePair<string,string>>(dataSource);
If you don't mind reaching into the objects internals, you could use the private Enumerable field on EnumerableQuery to get a version of (possibly) the original dictionary back as an IEnumerable<>
But to actually convert from an EnumerableQuery<KeyValuePair<int,int>> hiding under an IQueryable without doing that I think you'd have to just take the hit and create a new dictionary from it.
Related
I've got a Dictionary<Type, HashSet<GenericType>> which I use to hold my data in, and I am trying to make a function that returns one of those HashSets given the generic type T : GenericType.
Basically
Dictionary<Type, HashSet<GenericType>> data;
public HashSet<T> Get<T>() where T : GenericType
{
var tp = typeof(T);
//....check if its in the dictionary, fill if not....
return data[tp];
}
This isn't valid of course. But I am having a very hard time figuring out what I should do instead.
I feel like returning T is optimal though, since you then can do something like this:
Get<Derived>().Where(x => x.DerivedProperty == someValue)
But the only thing I thought of was to create a new HashSet<T> every time Get is called, and then using a foreach-loop cast and add every item from the already existing HashSet in the Dictionary, but this feels like such a waste?
Another idea is to skip HashSet and use another (covariant?) collection. But since these collections will hold lots of data, maybe it isn't the best idea either.
So in short I am wondering what the best approach for this problem is.
Update
So this is the structure I got. The type which contains data is a type of service in my code structure. It will via reflection be loaded and initialized at runtime. From there I later use a ServiceFactory of sorts to get that service.
public class foo : Service
{
public Dictionary<Type, HashSet<BaseClass>> data = new Dictionary<Type, HashSet<BaseClass>>();
public T Get<T>() where T : BaseClass
{
var tp = typeof(T);
if (!data.ContainsKey(tp))
{
data.Add(typeof(Derived), new HashSet<BaseClass>() { new Derived(), new Derived(), new Derived() });
}
return data[tp];//this wont compile.
}
}
public class Derived : BaseClass
{
public int ExampleVariable {get;set;}
}
public abstract class BaseClass
{
// some things in here.
public void DoCommonStuff()
{
}
}
class program
{
static void Main(string[] args)
{
var service = ServiceFactory.GetService<foo>();
var collection = service.Get<Derived>();
}
}
I would just change the type of the dictionary, and cast inside your Get method. Definitely, definitely make your dictionary private though - then you can make sure that only your code (ideally only the Get method) can access it:
// Any data[typeof(Foo)] value will be a HashSet<Foo>. Only
// the Get method should access this dictionary.
private readonly Dictionary<Type, object> data = new Dictionary<Type, object>();
public HashSet<T> Get<T>() where T : GenericType
{
var tp = typeof(T);
object value;
if (data.TryGetValue(tp, out value))
{
return (HashSet<T>) value;
}
var newSet = new HashSet<T>()
// Populate newSet here
data[tp] = newSet;
return newSet;
}
I have a bit more discussion of a closely-related issue in a blog post.
I am trying to give out a IReadOnly-references to internal Collection objects.
This works well in most cases, but does not if i want to convert a dictionary containing a collection into an IReadOnlyDictionary containing a IReadOnlyCollection.
Here a code example:
var list = new List<int>();
IReadOnlyList<int> listReference = list; //works;
var dictionary = new Dictionary<int, int>();
IReadOnlyDictionary<int, int> dictionaryReference = dictionary; //works
var nestedList = new List<List<int>>();
IReadOnlyList<IReadOnlyList<int>> nestedReadOnlyListReference = nestedList; //works
var nestedDictionary = new Dictionary<int, List<int>>();
//IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary; //does not work, can not implicitly convert
//current workaround
var nestedDictionaryReferenceHelper = new Dictionary<int, IReadOnlyList<int>>();
foreach (var kvpNestedDictionary in nestedDictionary)
{
nestedDictionaryReferenceHelper.Add(kvpNestedDictionary.Key, (IReadOnlyList<int>)kvpNestedDictionary.Value);
}
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionaryReferenceHelper; //works, but is only a reference to the internal List, not to the dictionary itself
The workaround is pretty ugly as it needs additional memory and needs manual updating every time the values of nestedDictionary change.
Is there any simple way to convert such nested dictionaries?
In this SO question you can find a very good explanation why casting dictionary values is not supported. Please see the accepted answer of Eric Lippert.
Although i would not recommend this, you could use the following LINQ expression to cast the values of the dictionary to a read only list:
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary.ToDictionary(kv => kv.Key, kv => kv.Value as IReadOnlyList<int>);
It is a shorter version of your workaround and it is lazy evaluated, but i would not recommend this due to the following reasons:
This solution still creates a copy of the dictionary and does not update any new/deleted entries from the original dictionary.
The values of the dictionary, i.e. the readonly lists, refer to the original lists and changes there are updated in the read only versions in the dictionary too.
This is inconsistent behavior and therefore a bad practice!
Unless it is not possible to cast the values of a dictionary, i would not recommend doing this. You should either deep copy the entire dictionary including the nested lists, or use an other container that supports casting.
In my opinion the point is the you're missing the opportunity to introduce a proper new type with its own dignity. If you're using Dictionary<int, List<int>> then you will see yourself with code like this every time you need to insert a value:
if (!_dictionary.ContainsKey(key)) {
var list = new List<int>();
list.Add(value);
_dictionary.Add(key, list);
} else {
_dictionary[key].Add(value);
}
And even worse with code like this when you want to search for a value:
_dictionary.ContainsKey(key) && _dictionary[key].Contains(value);
And variation of those examples. What's worse you're exposing this implementation detail to your class users. If this detail will change then you will break all code. What, for example, if you want to replace List<int> with HashSet<int>?
How it should be?
_multimap.Add(key, value);
With a proper interface (here I show just few methods):
public interface IMultiMap<TKey, TValue> {
void Add(TKey key, TValue value);
bool ContainsKey(TKey key);
}
And its implementation:
public sealed class MultiMap<TKey, TValue> : IMultiMap<TKey, TValue> {
// ...
private Dictionary<int, List<int>> _items;
}
You can introduce IReadOnlyMultiMap<TKey, TValue>:
public interface IReadOnlyMultiMap<TKey, TValue> {
bool ContainsKey(TKey key);
}
Just implement IReadOnlyMultiMap<TKey, TValue> in MultiMap<TKey, TValue> and to return a read-only collection you have nothing to do (fictional example):
IReadOnlyMultiMap<int, int> MakeReadOnly(MultiMap<int, int> map) {
return map; // Nothing to do!
}
Note that you may want to introduce a new ReadOnlyMultiMap<TKey, TValue> to tunnel read calls to underlying live collection (to avoid callers to simply cast to MultiMap<TKey, TValue> to circumvent read-only limitation). Proof of concept:
public sealed class ReadOnlyMultiMap<TKey, TValue> : IReadOnlyMultiMap<TKey, TValue> {
public ReadOnlyMultiMap(IMultiMap<TKey, TValue> collection) {
_collection = collection;
}
public bool ContainsKey(TKey key) {
return _collection.ContainsKey(key);
}
private readonly IMultiMap<TKey, TValue> _collection;
}
To return a read-only view you do:
IReadOnlyMultiMap<int, int> MakeReadOnly(MultiMap<int, int> map) {
return new ReadOnlyMultiMap<int, int>(map);
}
Note that I talked about implementation detail. You're still exposing an implementation detail (you're using a multimap) then if such code is for a public API you should introduce a new (properly named) type to describe what it contains, not how storage is implemented. It may be MeasureCollection, SoccerScoreCollection or whatever your model is talking about, storage may vary but content won't.
Problem for conversion failing is the KeyValuePair:
Although class Derived inheriting class Base, KeyValuePair is not a sub class of KeyValuePair; see definitions(Dictionary, IReadOnlyDictionary).
So you always will need some kind of workaround (MultiMap approach appears to me as one, too...). If nestedDictionary is private, so you have complete control over it from your class, you might get away with this:
var nestedDictionary = new Dictionary<int, IReadOnlyList<int>>();
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary;
and whenever modifying a list within the dictionary applying a cast to List<int>. Another ugly workaround, I admit, but saves you extra memory and redundancy management and retains the (asumed...) public interface of IReadOnlyDictionary<int, IReadOnlyList<int>>.
Edit: just an idea, haven't tested, but it might work: Have your own dictionary adding the missing interfaces to be assignable to the read-only dictionary:
public class MyDictionary
: Dictionary<int, List<int>>,
ICollection<KeyValuePair<int, IReadOnlyList<int>>,
IEnumerable<KeyValuePair<int, IReadOnlyList<int>>,
IReadOnlyCollection<KeyValuePair<int, IReadOnlyList<int>>
{
}
I might yet have missed an interface to be implemented, and you might have to implement some members yet. If it works, possibly the cleanest solution...
I am trying to give out a IReadOnly-references to internal Collection objects.
This works well in most cases, but does not if i want to convert a dictionary containing a collection into an IReadOnlyDictionary containing a IReadOnlyCollection.
Here a code example:
var list = new List<int>();
IReadOnlyList<int> listReference = list; //works;
var dictionary = new Dictionary<int, int>();
IReadOnlyDictionary<int, int> dictionaryReference = dictionary; //works
var nestedList = new List<List<int>>();
IReadOnlyList<IReadOnlyList<int>> nestedReadOnlyListReference = nestedList; //works
var nestedDictionary = new Dictionary<int, List<int>>();
//IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary; //does not work, can not implicitly convert
//current workaround
var nestedDictionaryReferenceHelper = new Dictionary<int, IReadOnlyList<int>>();
foreach (var kvpNestedDictionary in nestedDictionary)
{
nestedDictionaryReferenceHelper.Add(kvpNestedDictionary.Key, (IReadOnlyList<int>)kvpNestedDictionary.Value);
}
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionaryReferenceHelper; //works, but is only a reference to the internal List, not to the dictionary itself
The workaround is pretty ugly as it needs additional memory and needs manual updating every time the values of nestedDictionary change.
Is there any simple way to convert such nested dictionaries?
In this SO question you can find a very good explanation why casting dictionary values is not supported. Please see the accepted answer of Eric Lippert.
Although i would not recommend this, you could use the following LINQ expression to cast the values of the dictionary to a read only list:
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary.ToDictionary(kv => kv.Key, kv => kv.Value as IReadOnlyList<int>);
It is a shorter version of your workaround and it is lazy evaluated, but i would not recommend this due to the following reasons:
This solution still creates a copy of the dictionary and does not update any new/deleted entries from the original dictionary.
The values of the dictionary, i.e. the readonly lists, refer to the original lists and changes there are updated in the read only versions in the dictionary too.
This is inconsistent behavior and therefore a bad practice!
Unless it is not possible to cast the values of a dictionary, i would not recommend doing this. You should either deep copy the entire dictionary including the nested lists, or use an other container that supports casting.
In my opinion the point is the you're missing the opportunity to introduce a proper new type with its own dignity. If you're using Dictionary<int, List<int>> then you will see yourself with code like this every time you need to insert a value:
if (!_dictionary.ContainsKey(key)) {
var list = new List<int>();
list.Add(value);
_dictionary.Add(key, list);
} else {
_dictionary[key].Add(value);
}
And even worse with code like this when you want to search for a value:
_dictionary.ContainsKey(key) && _dictionary[key].Contains(value);
And variation of those examples. What's worse you're exposing this implementation detail to your class users. If this detail will change then you will break all code. What, for example, if you want to replace List<int> with HashSet<int>?
How it should be?
_multimap.Add(key, value);
With a proper interface (here I show just few methods):
public interface IMultiMap<TKey, TValue> {
void Add(TKey key, TValue value);
bool ContainsKey(TKey key);
}
And its implementation:
public sealed class MultiMap<TKey, TValue> : IMultiMap<TKey, TValue> {
// ...
private Dictionary<int, List<int>> _items;
}
You can introduce IReadOnlyMultiMap<TKey, TValue>:
public interface IReadOnlyMultiMap<TKey, TValue> {
bool ContainsKey(TKey key);
}
Just implement IReadOnlyMultiMap<TKey, TValue> in MultiMap<TKey, TValue> and to return a read-only collection you have nothing to do (fictional example):
IReadOnlyMultiMap<int, int> MakeReadOnly(MultiMap<int, int> map) {
return map; // Nothing to do!
}
Note that you may want to introduce a new ReadOnlyMultiMap<TKey, TValue> to tunnel read calls to underlying live collection (to avoid callers to simply cast to MultiMap<TKey, TValue> to circumvent read-only limitation). Proof of concept:
public sealed class ReadOnlyMultiMap<TKey, TValue> : IReadOnlyMultiMap<TKey, TValue> {
public ReadOnlyMultiMap(IMultiMap<TKey, TValue> collection) {
_collection = collection;
}
public bool ContainsKey(TKey key) {
return _collection.ContainsKey(key);
}
private readonly IMultiMap<TKey, TValue> _collection;
}
To return a read-only view you do:
IReadOnlyMultiMap<int, int> MakeReadOnly(MultiMap<int, int> map) {
return new ReadOnlyMultiMap<int, int>(map);
}
Note that I talked about implementation detail. You're still exposing an implementation detail (you're using a multimap) then if such code is for a public API you should introduce a new (properly named) type to describe what it contains, not how storage is implemented. It may be MeasureCollection, SoccerScoreCollection or whatever your model is talking about, storage may vary but content won't.
Problem for conversion failing is the KeyValuePair:
Although class Derived inheriting class Base, KeyValuePair is not a sub class of KeyValuePair; see definitions(Dictionary, IReadOnlyDictionary).
So you always will need some kind of workaround (MultiMap approach appears to me as one, too...). If nestedDictionary is private, so you have complete control over it from your class, you might get away with this:
var nestedDictionary = new Dictionary<int, IReadOnlyList<int>>();
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary;
and whenever modifying a list within the dictionary applying a cast to List<int>. Another ugly workaround, I admit, but saves you extra memory and redundancy management and retains the (asumed...) public interface of IReadOnlyDictionary<int, IReadOnlyList<int>>.
Edit: just an idea, haven't tested, but it might work: Have your own dictionary adding the missing interfaces to be assignable to the read-only dictionary:
public class MyDictionary
: Dictionary<int, List<int>>,
ICollection<KeyValuePair<int, IReadOnlyList<int>>,
IEnumerable<KeyValuePair<int, IReadOnlyList<int>>,
IReadOnlyCollection<KeyValuePair<int, IReadOnlyList<int>>
{
}
I might yet have missed an interface to be implemented, and you might have to implement some members yet. If it works, possibly the cleanest solution...
Hello this is my first post, don't be to hard if I do anything wrong :D
I am writing a DeSerializer for a big Programm,
To do so, I have a own Class
public class DeSerializeableElement
{
public Func<Object> action;
public Type type;
public DeSerializeableElement( Func<Object> p_action,Type p_type)
{
type = p_type;
action = p_action;
}
I read a String and then it always starts with 0XXX a 4 digit number.
with this number I get the right method from my
Dictionary<int,DeSerializableElement>
the initialize of the Dictionary is auto Generated and has 300 elements
deSerializableObjectDictionary.Add(276, new DeSerializeableElement(GetString, typeof(System.String)));
GetString is a method with no parameters and returns a String
Now my problem, if I Deserialize a List, at the moment I create a DeSerializableElement the Func looses its return value Information. Because I save it as Func so I get back a List
but it`s Important to get a List in case of GetString
there are also GetInt or GetDouble and lots more
So If i call GetList(GetString) I want as return value a List
and if I call GetList(GetInt) I want a List and so on.
But I get always a List because my SerializableElement has Func as attribute
The call for GetList looks like
GetList(deSerializableObjectDictionary[objectIdent].action);
GetList looks like
public IList<T> GetList<T>(Func<T> p_action) //T is always Object because of Func<Object> here I the right Type
{
IList<T> list = new List<T>();
ExpectToken('['); //The start Token of a serialized List
while (!IsNextToken(']')) //End Token of serialized List
{
list.Add(p_action());
}
return lst;
}
Any road you choose, it will one such that you are losing type safety. For example, you can defer to a Dictionary<int, object> and wrap that with a GetList<T> method where T is the actual type you want. A mis-use of this method can lead to runtime exceptions.
An example would be:
void Main()
{
var idToFunc = new Dictionary<int, object>();
idToFunc.Add(1, new DeSerializeableElement<int>(() => 1));
Console.WriteLine(GetList<int>(((DeSerializeableElement<int>) idToFunc[1]).Func));
}
public class DeSerializeableElement<T>
{
public Func<T> Func { get; set; }
public DeSerializeableElement(Func<T> func)
{
Func = func;
}
}
I would definitely of the risks involved with this kind of code. Although possible, I would advise you to re-think what you're doing and the architecture of your deserializer.
I'd like to create a Dictionary object, with string Keys, holding values which are of a generic type. I imagine that it would look something like this:
Dictionary<string, List<T>> d = new Dictionary<string, List<T>>();
And enable me to add the following:
d.Add("Numbers", new List<int>());
d.Add("Letters", new List<string>());
I know that I can do it for a list of strings, for example, using this syntax:
Dictionary<string, List<string>> d = new Dictionary<string, List<string>>();
d.Add("Key", new List<string>());
but I'd like to do it for a generic list if possible...
2 questions then:
Is it possible?
What's the syntax?
EDIT: Now I've reread the question...
You can't do this, but a custom collection would handle it to some extent. You'd basically have a generic Add method:
public void Add<T>(string key, List<T> list)
(The collection itself wouldn't be generic - unless you wanted to make the key type generic.)
You couldn't extract values from it in a strongly typed manner though, because the compiler won't know which type you've used for a particular key. If you make the key the type itself, you end with a slightly better situation, but one which still isn't supported by the existing collections. That's the situation my original answer was responding to.
EDIT: Original answer, when I hadn't quite read the question correctly, but which may be informative anyway...
No, you can't make one type argument depend on another, I'm afraid. It's just one of the things one might want to express in a generic type system but which .NET's constraints don't allow for. There are always going to be such problems, and the .NET designers chose to keep generics relatively simple.
However, you can write a collection to enforce it fairly easily. I have an example in a blog post which only keeps a single value, but it would be easy to extend that to use a list.
Would something like this work?
public class GenericDictionary
{
private Dictionary<string, object> _dict = new Dictionary<string, object>();
public void Add<T>(string key, T value) where T : class
{
_dict.Add(key, value);
}
public T GetValue<T>(string key) where T : class
{
return _dict[key] as T;
}
}
Basically it wraps all the casting behind the scenes for you.
How about Dictionary<string, dynamic>? (assuming you're on C# 4)
Dictionary<string, dynamic> Dict = new Dictionary<string, dynamic>();
Source: https://stackoverflow.com/a/5038029/3270733
I prefer this way of putting generic types into a collection:
interface IList
{
void Add (object item);
}
class MyList<T> : List<T>, IList
{
public void Add (object item)
{
base.Add ((T) item); // could put a type check here
}
}
class Program
{
static void Main (string [] args)
{
SortedDictionary<int, IList>
dict = new SortedDictionary<int, IList> ();
dict [0] = new MyList<int> ();
dict [1] = new MyList<float> ();
dict [0].Add (42);
dict [1].Add ("Hello"); // Fails! Type cast exception.
}
}
But you do lose the type checks at compile time.
I came to a type safe implementation using ConditionalWeakTable.
public class FieldByType
{
static class Storage<T>
where T : class
{
static readonly ConditionalWeakTable<FieldByType, T> table = new ConditionalWeakTable<FieldByType, T>();
public static T GetValue(FieldByType fieldByType)
{
table.TryGetValue(fieldByType, out var result);
return result;
}
public static void SetValue(FieldByType fieldByType, T value)
{
table.Remove(fieldByType);
table.Add(fieldByType, value);
}
}
public T GetValue<T>()
where T : class
{
return Storage<T>.GetValue(this);
}
public void SetValue<T>(T value)
where T : class
{
Storage<T>.SetValue(this, value);
}
}
It can be used like this:
/// <summary>
/// This class can be used when cloning multiple related objects to store cloned/original object relationship.
/// </summary>
public class CloningContext
{
readonly FieldByType dictionaries = new FieldByType();
public void RegisterClone<T>(T original, T clone)
{
var dictionary = dictionaries.GetValue<Dictionary<T, T>>();
if (dictionary == null)
{
dictionary = new Dictionary<T, T>();
dictionaries.SetValue(dictionary);
}
dictionary[original] = clone;
}
public bool TryGetClone<T>(T original, out T clone)
{
var dictionary = dictionaries.GetValue<Dictionary<T, T>>();
if (dictionary == null)
{
clone = default(T);
return false;
}
return dictionary.TryGetValue(original, out clone);
}
}
See also this question where the type of the values is stored in as a generic parameter of the keys.
We're using lots of reflection to create an extensible administration tool. We needed a way to register items in the global search in the module definition. Each search would return results in a consistent way, but each one had different dependencies. Here's an example of us registering search for a single module:
public void ConfigureSearch(ISearchConfiguration config)
{
config.AddGlobalSearchCallback<IEmploymentDataContext>((query, ctx) =>
{
return ctx.Positions.Where(p => p.Name.Contains(query)).ToList().Select(p =>
new SearchResult("Positions", p.Name, p.ThumbnailUrl,
new UrlContext("edit", "position", new RouteValueDictionary(new { Id = p.Id }))
));
});
}
In the background during module registration, we iterate over every module and add the Func to a SearchTable with an instance of:
public class GenericFuncCollection : IEnumerable<Tuple<Type, Type, Object>>
{
private List<Tuple<Type, Type, Object>> objects = new List<Tuple<Type, Type, Object>>();
/// <summary>
/// Stores a list of Func of T where T is unknown at compile time.
/// </summary>
/// <typeparam name="T1">Type of T</typeparam>
/// <typeparam name="T2">Type of the Func</typeparam>
/// <param name="func">Instance of the Func</param>
public void Add<T1, T2>(Object func)
{
objects.Add(new Tuple<Type, Type, Object>(typeof(T1), typeof(T2), func));
}
public IEnumerator<Tuple<Type, Type, object>> GetEnumerator()
{
return objects.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return objects.GetEnumerator();
}
}
Then when we finally call it, we do it with reflection:
var dependency = DependencyResolver.Current.GetService(search.Item1);
var methodInfo = search.Item2.GetMethod("Invoke");
return (IEnumerable<SearchResult>)methodInfo.Invoke(search.Item3, new Object[] { query, dependency });
I didn't find what I was looking for here but after reading I think it might be what is being asked for so an attempt to answer.
The problem is that when you use Dictionary it is a closed constructed type and all elements must be of the TValue type. I see this question in a number of places without a good answer.
Fact is that I want indexing but each element to have a different type and based on the value of TKey we already know the type. Not trying to get around the boxing but trying to simply get more elegant access something like DataSetExtensions Field. And don't want to use dynamic because the types are known and it is just not wanted.
A solution can be to create a non generic type that does not expose T at the class level and therefore cause the TValue part of the dictionary to be closed constructed. Then sprinkle in a fluent method to help initialization.
public class GenericObject
{
private object value;
public T GetValue<T>()
{
return (T)value;
}
public void SetValue<T>(T value)
{
this.value = value;
}
public GenericObject WithValue<T>(T value)
{
this.value = value;
return this;
}
}
class Program
{
static void Main(string[] args)
{
Dictionary<string, GenericObject> dict = new Dictionary<string, GenericObject>();
dict["mystring"] = new GenericObject().WithValue<string>("Hello World");
dict["myint"] = new GenericObject().WithValue<int>(1);
int i = dict["myint"].GetValue<int>();
string s = dict["mystring"].GetValue<string>();
}
}
Other posibility it's to use the variable dynamic.
For example:
Dictionary<string, List<dynamic>> d = new Dictionary<string, List<dynamic>>();
d.Add("Key", new List<dynamic>());
the variable dynamic resolve the type on runtime.
No, but you can use object instead of generic type.
Long answer:
The current version of C# will not allow you to make entries of generic type in a dictionary. Your options are either a) create a custom class that is the same as a dictionary except allow it to accept generic types, or b) make your Dictionary take values of type object. I find option b to be the simpler approach.
If you send lists of specific types, then when you go to process the lists you will have to test to see what kind of list it is. A better approach is to create lists of objects; this way you can enter integers, strings, or whatever data type you want and you don't necessarily have to test to see what type of object the List holds. This would (presumably) produce the effect you're looking for.
Here is a short console program that does the trick:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace dictionary
{
class Program
{
static void Main(string[] args)
{
Dictionary<string, object> dic = new Dictionary<string, object>();
var lstIntList = new List<object>();
var lstStrings = new List<object>();
var lstObjects = new List<object>();
string s = "";
lstIntList.Add(1);
lstIntList.Add(2);
lstIntList.Add(3);
lstStrings.Add("a");
lstStrings.Add("b");
lstStrings.Add("c");
dic.Add("Numbers", lstIntList);
dic.Add("Letters", lstStrings);
foreach (KeyValuePair<string, object> kvp in dic)
{
Console.WriteLine("{0}", kvp.Key);
lstObjects = ((IEnumerable)kvp.Value).Cast<object>().ToList();
foreach (var obj in lstObjects)
{s = obj.ToString(); Console.WriteLine(s);}
Console.WriteLine("");
}
Console.WriteLine("");
Console.WriteLine("press any key to exit");
Console.ReadKey();
}//end main
}
}
One of the way is to create a Dictionary value with type "object" like:
Dictionary<string, object> d = new Dictionary<string, object>();
So, here object datatype is used as a generic datatype, you can put anything in this as a value.
Or it's possible to use generic Type like this
public static void SafeUpdateInDictionary<T, L>(T DictionaryToBeUpdated, string Key, L Value) where T : Dictionary<string, L>
{
if (DictionaryToBeUpdated != null)
{
if(Value != null)
{
if (!DictionaryToBeUpdated.ContainsKey(Key))
DictionaryToBeUpdated.Add(Key, Value);
else
DictionaryToBeUpdated[Key] = Value;
}
}
}