Cannot use extension method for IDictionary<string, object> - c#

I have some already defined extension method like this:
public static object Get(this IDictionary<string, object> dict, string key)
{
if (dict.TryGetValue(key, out object value))
{
return value;
}
return null;
}
but if I try to use it with an instance of an
IDictionary <string, myClass>
it won't show up. I thought every class derived from object. Questions:
1) Why is this happening?
2) How could I make an extension method that includes all kinds of IDictionary?

This is perfectly working:
using System.Collections.Generic;
namespace ConsoleApp1
{
public class Program
{
public static void Main(string[] args)
{
var dic = new Dictionary<string, object> {{"Test", 1}};
var result = dic.Get("Test");
}
}
public static class MyExtensions
{
public static object Get(this IDictionary<string, object> dict, string key)
{
if (dict.TryGetValue(key, out object value))
{
return value;
}
return null;
}
public static T Get<T>(this IDictionary<string, T> dict, string key)
{
if (dict.TryGetValue(key, out T value))
{
return value;
}
return default(T);
}
}
}

Related

Generic type where T can be anything

Is it possible to write one generic c# method which will be look like this:
MyClass.Function1<string>()
MyClass.Function1<IEnumerable<string>>()
MyClass.Function1<IDictionary<string, string>>()
MyClass.Function1<IDictionary<string, IEnumerable<string>>>()
T can be anything
T = string
T = IEnumerable<string>
T = IDictionary<string, string>
T = IDictionary<string, IEnumerable<string>>
Second question
Can I create one static method will be not depends on type?
string GetSth().Function1();
IEnumerable<string> GetSth().Function1()
IDictionary<string, string> GetSth().Function1()
IDictionary<string, IEnumerable<string>> GetSth().Function1()
For First question define a generic class with where to shared interface such as IEnumerable or without any where clause :
public class MyClass
{
public static string Function1<T>()
{
return typeof(T).FullName;
}
public static string Function2<T>() where T : IEnumerable
{
return typeof(T).FullName;
}
}
And For second one define an Extension Methods :
public static class MyClass_Extensions
{
public static string StaticMethod1(this object obj)
{
return obj?.ToString();
}
public static string StaticMethod2(this IEnumerable obj)
{
return obj?.ToString();
}
}
So we can write this test method:
class Program
{
static void Main(string[] args)
{
Console.WriteLine(MyClass.Function1<string>());
Console.WriteLine(MyClass.Function1<IEnumerable<string>>());
Console.WriteLine(MyClass.Function1<IDictionary<string, string>>());
Console.WriteLine(MyClass.Function1<IDictionary<string, IEnumerable<string>>>());
Console.WriteLine(MyClass.Function2<string>());
Console.WriteLine(MyClass.Function2<IEnumerable<string>>());
Console.WriteLine(MyClass.Function2<IDictionary<string, string>>());
Console.WriteLine(MyClass.Function2<IDictionary<string, IEnumerable<string>>>());
// Static Method:
var strObj = "string";
Console.WriteLine(strObj.StaticMethod1());
Console.WriteLine(strObj.StaticMethod2());
IEnumerable<string> listObj = new List<string>();
Console.WriteLine(listObj.StaticMethod1());
Console.WriteLine(listObj.StaticMethod2());
IDictionary<string, string> dicObj = new Dictionary<string, string>();
Console.WriteLine(dicObj.StaticMethod1());
Console.WriteLine(dicObj.StaticMethod2());
IDictionary<string, IEnumerable<string>> dicLisObj = new Dictionary<string, IEnumerable<string>>();
Console.WriteLine(dicLisObj.StaticMethod1());
Console.WriteLine(dicLisObj.StaticMethod2());
}
}

Write Dictionary to XML doesn´t work

Well I asked before how to write an Dictionary to an File and was referenced to http://web.archive.org/web/20100703052446/http://blogs.msdn.com/b/psheill/archive/2005/04/09/406823.aspx
So, I am trying to use it but I have the Problem that it is always generating an empty File.
What am I doing wrong?
I have:
private static void Serialize(TextWriter writer, IDictionary dictionary)
{
List<Entry> entries = new List<Entry>(dictionary.Count);
foreach (object key in dictionary.Keys)
{
entries.Add(new Entry(key, dictionary[key]));
}
System.Xml.Serialization.XmlSerializer serializer = new XmlSerializer(typeof(List<Entry>));
serializer.Serialize(writer, entries);
}
private static void Deserialize(TextReader reader, IDictionary dictionary)
{
dictionary.Clear();
XmlSerializer serializer = new XmlSerializer(typeof(List<Entry>));
List<Entry> list = (List<Entry>)serializer.Deserialize(reader);
foreach (Entry entry in list)
{
dictionary[entry.Key] = entry.Value;
}
}
public class Entry
{
public object Key;
public object Value;
public Entry()
{
}
public Entry(object key, object value)
{
Key = key;
Value = value;
}
}
}
private void saveConfig()
{
TextWriter writer = File.CreateText("C:\\Users\\test.xml");
Serialize(writer, this.configuration);
}
private Dictionary<String, MyConfig> configuration;
where:
public class MyConfig{ public Item[] items=new Item[64];}
and Item.. is an pretty complex Object.
What am I doing wrong here? How get it to work? Or is it just not possible to pusth that Array in MyConfig to the FIle like that?
EDIT:
public class Item {
public Item(many params){}
uint whatever;
short whatever2;
byte bla;
String name,
List<Wrapper> wrappers;
ItemCache cache;
//many getters
}
public class ItemCache{
public ItemCache(many Params){}
List<CodeCache> cC;
}
public class Wrapper{
List<Cram> crams;
String name;
uint id;
}
The article you link to has a mistake. XmlSerializer requires that all types to be serialized are discoverable statically, in advance. The Entry class however has non-generic object keys and values, so this is not the case.
Instead, use generics, as doing so will statically specify they key and value types:
private static void Serialize<TKey, TValue>(TextWriter writer, IDictionary<TKey, TValue> dictionary)
{
var entries = dictionary.Select(pair => new Entry<TKey, TValue>(pair.Key, pair.Value)).ToList();
var serializer = new XmlSerializer(entries.GetType());
serializer.Serialize(writer, entries);
}
private static void Deserialize<TKey, TValue>(TextReader reader, IDictionary<TKey, TValue> dictionary)
{
var serializer = new XmlSerializer(typeof(List<Entry<TKey, TValue>>));
var list = (List<Entry<TKey, TValue>>)serializer.Deserialize(reader);
dictionary.Clear();
foreach (var entry in list)
{
dictionary[entry.Key] = entry.Value;
}
}
public class Entry<TKey, TValue>
{
public TKey Key;
public TValue Value;
public Entry() { }
public Entry(TKey key, TValue value)
{
Key = key;
Value = value;
}
}

How to set Dictionary as a property ? Give an example

I'm trying to use a dictionary as a class member. I want to
use a property to get/set the key/value of the dictionary but I'm
confused as how to use a dictionary as a property. Since there are 2
parts, I don't know how to setup the get/sets.
You could try this:
class Example {
private Dictionary<int,string> _map;
public Dictionary<int,string> Map { get { return _map; } }
public Example() { _map = new Dictionary<int,string>(); }
}
Implementation would go along the lines of:
var e = new Example();
e.Map[42] = "The Answer";
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
var cl = new cl();
populate(cl.dict);
foreach(var d in cl.dict)
Console.WriteLine(d.Key);
}
private static void populate(Dictionary<int, string> d)
{
for (int i = 0; i < 10 ; i++)
{
if (!d.ContainsKey(i))
{
d.Add(i, i.ToString());
}
}
}
}
public class cl
{
public Dictionary<int, string> dict;
public cl()
{
dict = new Dictionary<int, string>();
}
}
Do you mean this ?
class MyDictionary<TKey, TValue>
{
private readonly Dictionary<TKey, TValue> _dictionary;
public void Add(TKey key, TValue value)
{
_dictionary.Add(key, value);
}
public void Clear()
{
_dictionary.Clear();
}
public bool Remve(TKey key)
{
return _dictionary.Remove(key);
}
.... and other methods...
public MyDictionary(Dictionary<TKey, TValue> dictionary)
{
_dictionary = dictionary;
}
}

get keys from AppDomain.CurrentDomain.SetData()

I have implemented a very simple object cache in C# using AppDomain SetData() and GetData() like this (to reduce the number of DB calls for data that changes infrequently):
class Program
{
static void Main(string[] args)
{
List<string> users = (List<string>)GetUserList();
Console.ReadKey();
}
private static object GetUserList()
{
var users = AppDomain.CurrentDomain.GetData("GetUserList");
if (null == users)
{
users = new List<string>() { "apple", "banana" }; // dummy db results
AppDomain.CurrentDomain.SetData("GetUserList", users);
}
return users;
}
}
I now want to implement a simple PurgeCache() method iterate through the keys in my CurrentDomain and set the value to null.
How can I go about doing this?
EDIT
Based on Knaģis's reply, I have come up with the following.
ObjectCache.cs
class ObjectCache
{
private const string CacheName = "ObjectCache";
private static Dictionary<String, Object> Load()
{
Dictionary<string, object> myObjectCache = AppDomain.CurrentDomain.GetData(CacheName) as Dictionary<string, object>;
if (null == myObjectCache)
{
myObjectCache = new Dictionary<string, object>();
AppDomain.CurrentDomain.SetData(CacheName, myObjectCache);
}
return myObjectCache;
}
private static void Save(Object myObjectCache)
{
AppDomain.CurrentDomain.SetData(CacheName, myObjectCache);
}
public static void Purge()
{
Dictionary<string, object> myObjectCache = ObjectCache.Load();
myObjectCache.Clear();
ObjectCache.Save(myObjectCache);
}
public static void SetValue(String myKey, Object myValue)
{
Dictionary<string, object> myObjectCache = ObjectCache.Load();
myObjectCache[myKey] = myValue;
ObjectCache.Save(myObjectCache);
}
public static Object GetValue(String myKey)
{
Dictionary<string, object> myObjectCache = ObjectCache.Load();
return myObjectCache.ContainsKey(myKey) ? myObjectCache[myKey] : null;
}
}
Program.cs - Usage
class Program
{
static void Main(string[] args)
{
List<string> users = GetUserList<List<string>>();
ObjectCache.Purge(); // Removes Cache
Console.ReadKey();
}
private static T GetUserList<T>()
{
var users = ObjectCache.GetValue("GetUserList");
if (null == users) // No Cache
{
users = new List<string>() { "adam", "smith" }; // Dummy DB Results
ObjectCache.SetValue("GetUserList", users);
}
return (T)users;
}
}
AppDomain.GetData should not be used for caching purposes. Instead use solutions like System.Runtime.Caching. Or even just a static ConcurrentDictionary will be better.
If you insist on using AppDomain to store the values you should never delete everything in it - it stores information required by .NET framework to run properly.
Either store your values in a dictionary inside the AppDomain object or keep a list of keys yourself.
A simple in memory cache using a static dictionary (the second approach is for .NET 2.0 with explicit locks - note that this is very simple solution, there are better alternatives to locking):
using System;
using System.Collections.Concurrent;
namespace YourNamespace
{
public static class ObjectCache
{
private readonly static ConcurrentDictionary<string, object> Data = new ConcurrentDictionary<string, object>();
public static void SetValue(string key, object value)
{
Data[key] = value;
}
public static object GetValue(string key)
{
object t;
if (!Data.TryGetValue(key, out t))
return null;
return t;
}
public static void Purge()
{
Data.Clear();
}
}
public static class ObjectCache2
{
private readonly static Dictionary<string, object> Data = new Dictionary<string, object>();
public static void SetValue(string key, object value)
{
lock (Data)
Data[key] = value;
}
public static object GetValue(string key)
{
object t;
lock (Data)
{
if (!Data.TryGetValue(key, out t))
return null;
}
return t;
}
public static void Purge()
{
lock (Data)
Data.Clear();
}
}
}

Add Element to Dictionary of Lists

I have
Dictionary<string, List<int>> myDict = new Dictionary<string, List<int>>();
and at some points I want to add numbers to myDict for a specific Dictionary key.
I am currently doing
if (!myDict.ContainsKey(newKey)){
myDict[newKey] = new List<int>();
}
myDict[newKey].Add(myNumber);
but that seems to be error prone to forgetting the ContainsKey check at some point.
I have searched for a way to make Dictionaries return a new List in case myDict["entry"] doesn't exist yet, but I couldn't find anything.
Here's a relatively simple implementation of the LazyLookup example I mentioned. It only implements IEnumerable out of brevity/simplicity to answer the question.
Essentially, upon accessing an index, it will make sure it has already been initialized to a new instance of the List<T> class.
public class LazyLookup<TKey, TValue> : IEnumerable<List<TValue>>
{
private readonly Dictionary<TKey, List<TValue>> CachedEntries;
private readonly Func<List<TValue>> LazyListCreator;
public LazyLookup()
: this(() => new List<TValue>())
{
}
public LazyLookup(Func<List<TValue>> lazyListCreator)
{
this.LazyListCreator = lazyListCreator;
this.CachedEntries = new Dictionary<TKey, List<TValue>>();
}
public List<TValue> this[TKey key]
{
get
{
return GetOrCreateValue(key);
}
}
private List<TValue> GetOrCreateValue(TKey key)
{
List<TValue> returnValue;
if (!CachedEntries.TryGetValue(key, out returnValue))
{
returnValue = LazyListCreator();
CachedEntries[key] = returnValue;
}
return returnValue;
}
public IEnumerator<List<TValue>> GetEnumerator()
{
return CachedEntries.Values.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
With some usage:
var lazyLookup = new LazyLookup<string, int>();
lazyLookup["nocheck"].Add(9001);
//outputs 9001
Console.WriteLine(lazyLookup["nocheck"][0]);
//outputs 0 as it's a newly initialized list
Console.WriteLine(lazyLookup["someOtherLookup"].Count);
At this point, you could update it to be threadsafe (as GetOrCreateValue currently is not threadsafe), or generalize it so it doesn't assume it's of List<T> but any type, or extend it to implement the full IDictionary<TKey, TValue> interface. But at minimum, if the above pattern you posted is used often, you may consider swapping direct usage of the dictionaries with some encapsulation which trivializes the task for you and eliminates code duplication.
You can use TryGetValue:
List<int> list;
if(!myDict.TryGetValue(newKey, out list))
{
list = new List<int>();
myDict.Add(newKey, list);
}
list.Add(myNumber);
If the Dictionary is a field i would encapsulate the acces in a method:
Dictionary<string, List<int>> myDict = new Dictionary<string, List<int>>();
public void AddNumber(string key, int value)
{
List<int> list;
if(!myDict.TryGetValue(key, out list))
{
list = new List<int>();
myDict.Add(key, list);
}
list.Add(value);
}
If you use ConcurrentDictionary<T>, you can do this:
myDict.GetOrAdd(newKey, new List<int>()).Add(myNumber);
You can actually use the others' suggestions. By encapsulating the access in a method or even using ConcurrentDictionary.
But for me, I would have a custom dictionary so you can actually implement what myDict["entry"] does if it did not see an element.
Good thing with this is you have full control on how you would like this dictionary to behave.
class MyCustomDictionary<TKey, TValue> : IDictionary<TKey, TValue>
where TValue : class, new()
{
private Dictionary<TKey, TValue> _dictionary;
public MyCustomDictionary()
{
_dictionary = new Dictionary<TKey, TValue>();
}
public TValue this[TKey key] // this is what's important
{
get
{
TValue val;
if (!_dictionary.TryGetValue(key, out val)) // if there is no element for that key, add a new element and return it
{
_dictionary.Add(key, new TValue());
return _dictionary[key];
}
else // else return the found element
{
return val;
}
}
set
{
_dictionary[key] = value;
}
}
public void Add(TKey key, TValue value)
{
_dictionary.Add(key, value);
}
public bool ContainsKey(TKey key)
{
return _dictionary.ContainsKey(key);
}
public ICollection<TKey> Keys
{
get { return _dictionary.Keys; }
}
public bool Remove(TKey key)
{
return _dictionary.Remove(key);
}
public bool TryGetValue(TKey key, out TValue value)
{
return _dictionary.TryGetValue(key, out value);
}
public ICollection<TValue> Values
{
get { return _dictionary.Values; }
}
public void Add(KeyValuePair<TKey, TValue> item)
{
_dictionary.Add(item.Key, item.Value);
}
public void Clear()
{
_dictionary.Clear();
}
public bool Contains(KeyValuePair<TKey, TValue> item)
{
return _dictionary.Contains(item);
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
_dictionary.ToList().CopyTo(array, arrayIndex); // do you need this? you can leave this :)
}
public int Count
{
get { return _dictionary.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(KeyValuePair<TKey, TValue> item)
{
return _dictionary.Remove(item.Key);
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return _dictionary.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _dictionary.GetEnumerator();
}
}
Then you use it like:
MyCustomDictionary<string, List<int>> myCustomDict = new MyCustomDictionary<int, List<int>>();
// return a new List of int
var someElementThatIsNotFound = myCustomDict["keyThatIsNonExistent"];
You can use TryGetValue method: if there's the key in the dictionary
you should just add the value into the list; otherwise you should
add a list with a value:
List<int> list
if (myDict.TryGetValue(newKey, out list))
list.Add(myNumber);
else
myDict.Add(newKey, new List<int>() { myNumber });
Lots of good answers already. I implemented an extension method for this exact reason:
public static TVALUE GetOrSet<TKEY, TVALUE>(this IDictionary<TKEY, TVALUE> self,
TKEY key,
Func<TVALUE> defaultValue)
{
TVALUE value;
if (!self.TryGetValue(key, out value))
{
value = defaultValue();
self[key] = value;
}
return value;
} // eo GetOrSet
Note that it takes a function to assign the value if it is not present. Either way, the value will be returned. Usage:
var dict = new Dictionary<string, List<int>>();
List<int> ints = dict.GetOrSet("list1", () => return new List<int>());
ints.Add(1);
If you're not referencing it again, you could potentially be less verbose:
dict.GetOrSet("list1", () => return new List<int>()).Add(1);

Categories