Dictionary of derived objects - c#

I have a config with thousands of EnumValues and I parse them in runtime
void DoSmth()
{
foreach (var line in configLines)
{
var myEnumValue = (MyEnum) Enum.Parse(line);
...
}
}
and I can improve perfomance by creating a map between a string from the config and an actual enumValue
Dictionary<string, MyEnum> dict = new();
void DoSmth()
{
foreach (var line in configLines)
{
if (!dict.ContainsKey(line)
dict.Add(line, (MyEnum) Enum.Parse(typeof(MyEnum), line));
var myEnumValue = dict[line];
...
}
}
Q:
Is there any way (maybe using some co/contravariance magic) to create a generic function so it could create such dictionaries dynamically to avoid writing the same caching code over and over again?
e.g.
void DoSmth()
{
foreach (var line in configLines)
{
var myEnumValue = MyExtensions.Parse<MyEnum>(line);
...
}
}
class MyExtensions
{
Dictionary<Type, Dictionary<string, EnumValue> _cachedEnumValues; // < EnumValue type not exists, so how to?
public T Parse<T>(string s) where T : Enum
{
if (!_cachedEnumValues.ContansKey(typeof(T))
_cachedEnumValues.Add(typeof(T), new Dictionary<string, T>();
if (!_cachedEnumValues[typeof(T)].ContansKey(s))
_cachedEnumValues[typeof(T)].Add(s, (MyEnum) Enum.Parse(typeof(MyEnum), s);
return _cachedEnumValues[typeof(T)][s];
}
}

Sure:
public sealed class EnumHelper<T> where T : Enum
{
private static readonly ConcurrentDictionary<string, T> Cache = new ConcurrentDictionary<string, T>(StringComparer.OrdinalIgnoreCase);
public static T Parse(string s)
{
return Cache.GetOrAdd(s, k => (T)Enum.Parse(typeof(T), k));
}
}
Usage:
var t = EnumHelper<SearchOption>.Parse(SearchOption.AllDirectories.ToString());

Related

Generic Dictionary value is an Generic Dictionary

I'd like to create a class which contains a generic dictionary which value is an generic dictionary as below:
class DList<T>
{
public Dictionary<string, Dictionary<K, T>> Dic;
public Init<K,T>()
{
Dic = new Dictionary<string, Dictionary<K, T>>();
Dic.Add("Name", new Dictionary<string, T>());
Dic.Add("Id", new Dictionary<int, T>());
}
}
How can I implement this? Thanks a lot
dynamic works. What I need is almost like a multi-keys Dictionary.
public class DList<T> : IEnumerable
{
private List<T> list;
private Dictionary<string, dynamic> dic;
public T this[int i] => list[i];
public dynamic this[string j] => dic[j];
public int Count => list.Count;
public DList(params string[] properties)
{
this.list = new List<T>();
this.dic = new Dictionary<string, dynamic>();
foreach (var item in properties)
{
this.dic.Add(item, new Dictionary<dynamic, T>());
}
}
public void Add(T t)
{
list.Add(t);
foreach (var item in dic)
{
dynamic d = t.GetType()
.GetField(item.Key)
.GetValue(t);
if (item.Value.ContainsKey(d))
continue;
item.Value.Add(d, t);
}
}
public T Get(string key, dynamic s)
{
return dic[key][s];
}
public T Get(int index)
{
return list[index];
}
public void Clear()
{
this.list.Clear();
foreach(var item in dic)
{
item.Value.Clear();
}
}
public void Sort(Comparison<T> Compare)
{
list.Sort(Compare);
}
public IEnumerator GetEnumerator()
{
return list.GetEnumerator();
}
}
class DList<K, T>
{
public Dictionary<string, Dictionary<K, T>> Dic;
public DList()
{
Dic = new Dictionary<string, Dictionary<K, T>>();
Dic.Add("Name", new Dictionary<K, T>());
Dic.Add("Id", new Dictionary<K, T>());
}
}
class DList2<K, T>
{
public Dictionary<string, Dictionary<object, T>> Dic;
public DList2()
{
Dic = new Dictionary<string, Dictionary<object, T>>();
Dic.Add("Name", new Dictionary<object, T>());
Dic.Add("Id", new Dictionary<object, T>());
}
}
If you know K upfront, use the DList approach. If you want to use string, int etc for K, use the approach in DList2. The inner dictionary will work just fine with keys of type int, string, etc, even if its key is declared as object.

C#: Exposing type safe API over heterogeneous dictionary

I'd like to expose a type safe API over a particular JSON format. Here is basically what I have so far:
public class JsonDictionary
{
Dictionary<string, Type> _keyTypes = new Dictionary<string, Type> {
{ "FOO", typeof(int) },
{ "BAR", typeof(string) },
};
IDictionary<string, object> _data;
public JsonDictionary()
{
_data = new Dictionary<string, object>();
}
public void Set<T>(string key, T obj)
{
if (typeof(T) != _keyTypes[key])
throw new Exception($"Invalid type: {typeof(T)} vs {_keyTypes[key]}");
_data[key] = obj;
}
public dynamic Get(string key)
{
var value = _data[key];
if (value.GetType() != _keyTypes[key])
throw new Exception($"Invalid type: {value.GetType()} vs {_keyTypes[key]}");
return value;
}
}
Which can be used nicely as:
JsonDictionary d = new JsonDictionary();
d.Set("FOO", 42);
d.Set("BAR", "value");
However reading the value is a little disapointing and rely on late binding:
var i = d.Get("FOO");
var s = d.Get("BAR");
Assert.Equal(42, i);
Assert.Equal("value", s);
Is there some C# magic that I can use to implement a type-safe generic Get<T> instead of relying on dynamic here (ideally type should be checked at compilation time) ? I'd like to also use the pattern for Set<T> so that d.Set("BAR", 56); triggers a compilation warning.
Dictionary<string, Type> _keyTypes can be made static if needed. The above is just work in progress.
I was using solution similar to this:
public class JsonDictionary
{
public static readonly Key<int> Foo = new Key<int> { Name = "FOO" };
public static readonly Key<string> Bar = new Key<string> { Name = "BAR" };
IDictionary<string, object> _data;
public JsonDictionary()
{
_data = new Dictionary<string, object>();
}
public void Set<T>(Key<T> key, T obj)
{
_data[key.Name] = obj;
}
public T Get<T>(Key<T> key)
{
return (T)_data[key.Name];
}
public sealed class Key<T>
{
public string Name { get; init; }
}
}
I would convert T to object and check object type with .GetType()
public class JsonDictionary
{
Dictionary<string, Type> _keyTypes = new Dictionary<string, Type> {
{ "FOO", typeof(int) },
{ "BAR", typeof(string) },
};
IDictionary<string, object> _data;
public JsonDictionary()
{
_data = new Dictionary<string, object>();
}
public void Set(string key, object obj)
{
if (obj.GetType() != _keyTypes[key])
throw new Exception($"Invalid type: {obj.GetType()} vs {_keyTypes[key]}");
_data[key] = obj;
}
public object Get(string key)
{
return _data[key];
}
}
I tried it like this and it worked:
JsonDictionary d = new JsonDictionary();
d.Set("FOO", 42);
d.Set("BAR", "value");
var i = d.Get("FOO");
var s = d.Get("BAR");
Console.WriteLine(i);
Console.WriteLine(s);
But to be honest, I don't like what you are trying to achieve.

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());
}
}

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;
}
}

C# generic method returning different object instances [duplicate]

Are there any elegant quick way to map object to a dictionary and vice versa?
Example:
IDictionary<string,object> a = new Dictionary<string,object>();
a["Id"]=1;
a["Name"]="Ahmad";
// .....
becomes
SomeClass b = new SomeClass();
b.Id=1;
b.Name="Ahmad";
// ..........
Using some reflection and generics in two extension methods you can achieve that.
Right, others did mostly the same solution, but this uses less reflection which is more performance-wise and way more readable:
public static class ObjectExtensions
{
public static T ToObject<T>(this IDictionary<string, object> source)
where T : class, new()
{
var someObject = new T();
var someObjectType = someObject.GetType();
foreach (var item in source)
{
someObjectType
.GetProperty(item.Key)
.SetValue(someObject, item.Value, null);
}
return someObject;
}
public static IDictionary<string, object> AsDictionary(this object source, BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)
{
return source.GetType().GetProperties(bindingAttr).ToDictionary
(
propInfo => propInfo.Name,
propInfo => propInfo.GetValue(source, null)
);
}
}
class A
{
public string Prop1
{
get;
set;
}
public int Prop2
{
get;
set;
}
}
class Program
{
static void Main(string[] args)
{
Dictionary<string, object> dictionary = new Dictionary<string, object>();
dictionary.Add("Prop1", "hello world!");
dictionary.Add("Prop2", 3893);
A someObject = dictionary.ToObject<A>();
IDictionary<string, object> objectBackToDictionary = someObject.AsDictionary();
}
}
Convert the Dictionary to JSON string first with Newtonsoft.
var json = JsonConvert.SerializeObject(advancedSettingsDictionary, Newtonsoft.Json.Formatting.Indented);
Then deserialize the JSON string to your object
var myobject = JsonConvert.DeserializeObject<AOCAdvancedSettings>(json);
Seems reflection only help here.. I've done small example of converting object to dictionary and vise versa:
[TestMethod]
public void DictionaryTest()
{
var item = new SomeCLass { Id = "1", Name = "name1" };
IDictionary<string, object> dict = ObjectToDictionary<SomeCLass>(item);
var obj = ObjectFromDictionary<SomeCLass>(dict);
}
private T ObjectFromDictionary<T>(IDictionary<string, object> dict)
where T : class
{
Type type = typeof(T);
T result = (T)Activator.CreateInstance(type);
foreach (var item in dict)
{
type.GetProperty(item.Key).SetValue(result, item.Value, null);
}
return result;
}
private IDictionary<string, object> ObjectToDictionary<T>(T item)
where T: class
{
Type myObjectType = item.GetType();
IDictionary<string, object> dict = new Dictionary<string, object>();
var indexer = new object[0];
PropertyInfo[] properties = myObjectType.GetProperties();
foreach (var info in properties)
{
var value = info.GetValue(item, indexer);
dict.Add(info.Name, value);
}
return dict;
}
I'd highly recommend the Castle DictionaryAdapter, easily one of that project's best-kept secrets. You only need to define an interface with the properties you want, and in one line of code the adapter will generate an implementation, instantiate it, and synchronize its values with a dictionary you pass in. I use it to strongly-type my AppSettings in a web project:
var appSettings =
new DictionaryAdapterFactory().GetAdapter<IAppSettings>(ConfigurationManager.AppSettings);
Note that I did not need to create a class that implements IAppSettings - the adapter does that on the fly. Also, although in this case I'm only reading, in theory if I were setting property values on appSettings, the adapter would keep the underlying dictionary in sync with those changes.
I think you should use reflection. Something like this:
private T ConvertDictionaryTo<T>(IDictionary<string, object> dictionary) where T : new()
{
Type type = typeof (T);
T ret = new T();
foreach (var keyValue in dictionary)
{
type.GetProperty(keyValue.Key).SetValue(ret, keyValue.Value, null);
}
return ret;
}
It takes your dictionary and loops through it and sets the values. You should make it better but it's a start. You should call it like this:
SomeClass someClass = ConvertDictionaryTo<SomeClass>(a);
Reflection can take you from an object to a dictionary by iterating over the properties.
To go the other way, you'll have to use a dynamic ExpandoObject (which, in fact, already inherits from IDictionary, and so has done this for you) in C#, unless you can infer the type from the collection of entries in the dictionary somehow.
So, if you're in .NET 4.0 land, use an ExpandoObject, otherwise you've got a lot of work to do...
Building on Matías Fidemraizer's answer, here is a version that supports binding to object properties other than strings.
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace WebOpsApi.Shared.Helpers
{
public static class MappingExtension
{
public static T ToObject<T>(this IDictionary<string, object> source)
where T : class, new()
{
var someObject = new T();
var someObjectType = someObject.GetType();
foreach (var item in source)
{
var key = char.ToUpper(item.Key[0]) + item.Key.Substring(1);
var targetProperty = someObjectType.GetProperty(key);
//edited this line
if (targetProperty.PropertyType == item.Value.GetType())
{
targetProperty.SetValue(someObject, item.Value);
}
else
{
var parseMethod = targetProperty.PropertyType.GetMethod("TryParse",
BindingFlags.Public | BindingFlags.Static, null,
new[] {typeof (string), targetProperty.PropertyType.MakeByRefType()}, null);
if (parseMethod != null)
{
var parameters = new[] { item.Value, null };
var success = (bool)parseMethod.Invoke(null, parameters);
if (success)
{
targetProperty.SetValue(someObject, parameters[1]);
}
}
}
}
return someObject;
}
public static IDictionary<string, object> AsDictionary(this object source, BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)
{
return source.GetType().GetProperties(bindingAttr).ToDictionary
(
propInfo => propInfo.Name,
propInfo => propInfo.GetValue(source, null)
);
}
}
}
public class SimpleObjectDictionaryMapper<TObject>
{
public static TObject GetObject(IDictionary<string, object> d)
{
PropertyInfo[] props = typeof(TObject).GetProperties();
TObject res = Activator.CreateInstance<TObject>();
for (int i = 0; i < props.Length; i++)
{
if (props[i].CanWrite && d.ContainsKey(props[i].Name))
{
props[i].SetValue(res, d[props[i].Name], null);
}
}
return res;
}
public static IDictionary<string, object> GetDictionary(TObject o)
{
IDictionary<string, object> res = new Dictionary<string, object>();
PropertyInfo[] props = typeof(TObject).GetProperties();
for (int i = 0; i < props.Length; i++)
{
if (props[i].CanRead)
{
res.Add(props[i].Name, props[i].GetValue(o, null));
}
}
return res;
}
}
If you are using Asp.Net MVC, then take a look at:
public static RouteValueDictionary AnonymousObjectToHtmlAttributes(object htmlAttributes);
which is a static public method on the System.Web.Mvc.HtmlHelper class.
public Dictionary<string, object> ToDictionary<T>(string key, T value)
{
try
{
var payload = new Dictionary<string, object>
{
{ key, value }
};
} catch (Exception e)
{
return null;
}
}
public T FromDictionary<T>(Dictionary<string, object> payload, string key)
{
try
{
JObject jObject = (JObject) payload[key];
T t = jObject.ToObject<T>();
return (t);
}
catch(Exception e) {
return default(T);
}
}

Categories