patterncsharpModerate
Type-safe Dictionary for various types
Viewed 0 times
typeforsafetypesdictionaryvarious
Problem
Assume the following situation: you have an object that can store any object based on a key (basically,
I don't want to create a single class that will contain all those objects, because they are not directly related, they come from different places. But if you store each object separately, it means you have to use casts when getting some value and there is no type-check when you're setting it.
To solve this, I created a generic type that encapsulates the key along with the associated type and a couple of extension methods that use it:
Usage:
This has the type-safety (both on get and set) of using a property, while being backed by a dictionary that can store anything.
What do you think about this pattern?
IDictionary). You want to store objects of various types into it that are not directly related. (For example, the dictionary can be an ASP.NET Session, or it can represent a dictionary that will be serialized to disk for persistent storage.)I don't want to create a single class that will contain all those objects, because they are not directly related, they come from different places. But if you store each object separately, it means you have to use casts when getting some value and there is no type-check when you're setting it.
To solve this, I created a generic type that encapsulates the key along with the associated type and a couple of extension methods that use it:
class TypedKey
{
public string Name { get; private set; }
public TypedKey(string name)
{
Name = name;
}
}
static class DictionaryExtensions
{
public static T Get(this IDictionary dictionary, TypedKey key)
{
return (T)dictionary[key.Name];
}
public static void Set(this IDictionary dictionary, TypedKey key, T value)
{
dictionary[key.Name] = value;
}
}Usage:
private static readonly TypedKey AgeKey = new TypedKey("age");
…
dictionary.Get(AgeKey) > 18
dictionary.Set(AgeKey, age)This has the type-safety (both on get and set) of using a property, while being backed by a dictionary that can store anything.
What do you think about this pattern?
Solution
Your suggestion is not really type-safe as you can still pass a key of the wrong type. Therefore I would just use a normal (string) key. But I would add a generic
You can then use the dictionary like this.
Note that the compiler can infer the generic type when using
UPDATE
In despite of my suggestion above, I must agree that your solution is elegant. Here is another suggestion which is based on your solution but which encapsulates the dictionary instead of providing a key. Well, it acts as wrapper and as key at the same time
Alternatively, a string key could be provided in the Property's constructor.
You can use it like this
TryGet method which takes account of the type. The setter needs not to be generic. static class DictionaryExtensions
{
public static T Get(this IDictionary dictionary, string key)
{
return (T)dictionary[key];
}
public static bool TryGet(this IDictionary dictionary,
string key, out T value)
{
object result;
if (dictionary.TryGetValue(key, out result) && result is T) {
value = (T)result;
return true;
}
value = default(T);
return false;
}
public static void Set(this IDictionary dictionary,
string key, object value)
{
dictionary[key] = value;
}
}You can then use the dictionary like this.
int age = 20;
dictionary.Set("age", age);
// ...
age = dictionary.Get("age");
// or the safe way
if (dictionary.TryGet("age", out age)) {
Console.WriteLine("The age is {0}", age);
} else {
Console.WriteLine("Age not found or of wrong type");
}Note that the compiler can infer the generic type when using
TryGet.UPDATE
In despite of my suggestion above, I must agree that your solution is elegant. Here is another suggestion which is based on your solution but which encapsulates the dictionary instead of providing a key. Well, it acts as wrapper and as key at the same time
public class Property
{
Dictionary _dict;
public Property (Dictionary dict)
{
_dict = dict;
}
public T Value {
get { return (T)_dict[this]; }
set { _dict[this] = value; }
}
}Alternatively, a string key could be provided in the Property's constructor.
You can use it like this
private static readonly Dictionary _properties =
new Dictionary();
private static readonly Property _age = new Property(_properties);
...
_age.Value > 18
_age.Value = ageCode Snippets
static class DictionaryExtensions
{
public static T Get<T>(this IDictionary<string, object> dictionary, string key)
{
return (T)dictionary[key];
}
public static bool TryGet<T>(this IDictionary<string, object> dictionary,
string key, out T value)
{
object result;
if (dictionary.TryGetValue(key, out result) && result is T) {
value = (T)result;
return true;
}
value = default(T);
return false;
}
public static void Set(this IDictionary<string, object> dictionary,
string key, object value)
{
dictionary[key] = value;
}
}int age = 20;
dictionary.Set("age", age);
// ...
age = dictionary.Get<int>("age");
// or the safe way
if (dictionary.TryGet("age", out age)) {
Console.WriteLine("The age is {0}", age);
} else {
Console.WriteLine("Age not found or of wrong type");
}public class Property<T>
{
Dictionary<object, object> _dict;
public Property (Dictionary<object, object> dict)
{
_dict = dict;
}
public T Value {
get { return (T)_dict[this]; }
set { _dict[this] = value; }
}
}private static readonly Dictionary<object, object> _properties =
new Dictionary<object, object>();
private static readonly Property<int> _age = new Property<int>(_properties);
...
_age.Value > 18
_age.Value = ageContext
StackExchange Code Review Q#12291, answer score: 17
Revisions (0)
No revisions yet.