70

I need some sort of way to store key/value pairs where the value can be of different types.

So I like to do:

 int i = 12;
 string s = "test";
 double x = 24.1;

 Storage.Add("age", i);
 Storage.Add("name", s);
 Storage.Add("bmi", x);

And later retrieve the values with:

 int a = Storage.Get("age");
 string b = Storage.Get("name");
 double c = Storage.Get("bmi");

How should a Storage like this look like? Thanks, Erik

Enrico
  • 1,937
  • 3
  • 27
  • 40

8 Answers8

93

Well, you could use Dictionary<string, dynamic> in C# 4 / .NET 4 - but other than that, you can't do it with exactly the code shown because there's no type which is implicitly convertible to int, string and double. (You could write your own one, but you'd have to list each type separately.)

You could use Dictionary<string, object> but then you'd need to cast the results:

int a = (int) Storage.Get("age");
string b = (string) Storage.Get("name");
double c = (double) Storage.Get("bmi");

Alternatively, you could make the Get method generic:

int a = Storage.Get<int>("age");
// etc
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Perhaps someone should create a Variant type? HELP, I'M BLIND! – Lasse V. Karlsen Nov 05 '10 at 11:55
  • 2
    I agree with Jon Skeet. Again. But doing something like this means you are doing something wrong. You should first think about reasons behind why you need to store different values in single dictionary. – Euphoric Nov 05 '10 at 11:58
  • Thanks a lot, the generic Get method was the thing I was looking for!! – Enrico Nov 05 '10 at 12:20
  • Agree wtih Euphoric, would that be easier if just change the dictionary to an Object, and each of value in the list can be a member. Even though it is less dynamic(say you have a large number of uncertain values in the list), it is type safe and easier to maintain. – anIBMer Dec 09 '13 at 00:58
  • @Euphoric A `dictionary` declaration compiles and access of dictionary values requires unboxing, which is not performant. I can see how it leads to more complex code (additional logic to ensure container access doesn't throw exceptions), but can't we say that it simply offers the most flexibility in typing at the cost of performance and complexity? An application requiring flexibility might accept that tradeoff. – Minh Tran Oct 24 '18 at 14:58
  • [This](https://msdn.microsoft.com/en-us/library/ms379564%28v=vs.80%29.aspx?f=255&MSPPError=-2147217396) article discuss why using `object` is not "type-safe", why generics are preferred, and so we begin to see why `Dictionary` is not such a great idea. – Minh Tran Oct 24 '18 at 15:41
  • 4
    @MinhTran: Unless you *need* to store a variety of values, of course. While it's great if you *can* make things type-safe, there are all kinds of situations where you really can't. – Jon Skeet Oct 24 '18 at 15:53
  • Am I the only dummy who is confused about the 'Get' method being used? I can't seem to find a .NET collection type that implements this. Maybe it's implemented in a user class (named Storage) that wraps the dictionary? – B H Jan 16 '20 at 18:26
  • 1
    @BH You need to create the generic extension over `Dictionary`. It is not there part of .NET so you are not crazy – Franck Aug 17 '20 at 15:15
  • @Euphoric, 12 years late to the game but we were doing this with ADO.NET DataRows in past 22 years. they return bunch of different types in a dictionary (in a manner of speaking) that is accessible like Row["intType"], Row["stringType"] however return type is still object and a conversion is required. Would be amazing if we could have them already converted to their original types like the way they are stored in SQL server for example. – AaA Aug 26 '22 at 03:38
  • @AaA: The *actual* type is already an appropriate type - but how would you expect the *compile-time* type to be "right", given that the type depends on the value passed to the indexer? – Jon Skeet Aug 26 '22 at 06:50
  • @JonSkeet, Not sure if that would be possible on compile time. I guess it can be achieved on runtime or design time. With PHP arrays can hold different types. With C, C++ I can get a value depending even if might not be the one I want (pointers). With Javascript objects properties can be added to them and are readable with both notions of obj.prop or obj[prop] (behave like an indexer maybe). With C# we have `var` that compiler can figure out what is the actual type, I don't see why it can't do same with dictionary contents? – AaA Sep 21 '22 at 09:22
  • @AaA: What do you mean by "design time" that you expect to be different to "compile time"? It's fine to have a dictionary with different kinds of values, e.g. `Dictionary`. But you shouldn't expect the compiler to understand that `dict["foo"]` should be of type `Bar`, but `dict["baz"]` should be of type `Qux`. But hey, if you don't care about compile-time type checking, just use `dynamic`... – Jon Skeet Sep 21 '22 at 17:58
34

You could declare a Dictionary containing just the type object and then cast your results; .e.g.

Dictionary<string, object> storage = new Dictionary<string,object>();

storage.Add("age", 12);
storage.Add("name", "test");
storage.Add("bmi", 24.1);

int a = (int)storage["age"];
string b = (string)storage["name"];
double c = (double)storage["bmi"];

However, this isn't that elegant. If you know you are always going to be storing age, name, bmi I would create an object to encapsulate those and store that instead. E.g.

public class PersonInfo
{
    public int Age { get; set; }
    public string Name { get; set; }
    public double Bmi { get; set; }
}

And then use that insead of the Dictionary... e.g.

PersonInfo person1 = new PersonInfo { Name = "test", Age = 32, Bmi = 25.01 };

int age = person1.Age;

etc.

depperm
  • 10,606
  • 4
  • 43
  • 67
Steve
  • 8,469
  • 1
  • 26
  • 37
12

Why not use:

Dictionary<string, object>

You can create an extension method to cast values when you get them:

public static class DictionaryExtensions
{
    public static T Get<T>(this Dictionary<string, object> instance, string name)
    {
        return (T)instance[name];
    }

}

var age = dictionary.Get<int>("age");
Anil
  • 655
  • 1
  • 11
  • 25
jgauffin
  • 99,844
  • 45
  • 235
  • 372
5

Given that you don't want a strongly typed data collection then I would have thought a HashTable would be suitable for your situation. You could create an Extention method for this also, like another poster suggested for the Dictionary implementation.

E.g.

public static class StorageExtentions
{
    public static T Get<T>(this Hashtable table, object key)
    {
        return (T) table[key];
    }
}

Your code would then look like:

int i = 12;
string s = "test";
double x = 24.1;
Hashtable Storage = new Hashtable();
Storage.Add("age", i);
Storage.Add("name", s);
Storage.Add("bmi", x);
int a = Storage.Get<int>("age");
string b = Storage.Get<string>("name");
double c = Storage.Get<double>("bmi");
depperm
  • 10,606
  • 4
  • 43
  • 67
John Pappin
  • 578
  • 3
  • 11
4

maybe it is an old question, but I am addressing the guys who come here to find the answer

if the value is not a fixed type one of the choices is using Hashtable please look at the implementation of both Dictionary and Hashtable

    public class Dictionary<TKey, TValue> : ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable, IDictionary<TKey, TValue>, IReadOnlyCollection<KeyValuePair<TKey, TValue>>, IReadOnlyDictionary<TKey, TValue>, ICollection, IDictionary, IDeserializationCallback, ISerializable
     {
              ... 
     }

public class Hashtable : ICollection, IEnumerable, IDictionary, ISerializable, IDeserializationCallback, ICloneable
  {
   ...
  }

as it gets more clear from above code snippets, both implement literally the same interfaces but in Hashtable there is no type on both key & value since both of them considered to be intrinsically objects, for example you can see from add method in Hashtable:

public virtual void Add(object key, object value);

so for the cases of not having fixed keys and/or values, I recommend using Hashtable, therefore you don't need to add extra extension methods or override default behavior of a dictionary any more.

2
Dictionary<string, object>
Nikola Smiljanić
  • 26,745
  • 6
  • 48
  • 60
1

You can use a Dictionary<string,object> and then you can put anything you want into it. You would have to cast the results to the right type when you get them out though.

Looking at your example though you might want to consider whether a simple class to store the data might be more what you want and allow better type safety. It depends on whether you have a limited set of things to put in the class or if you do need the potentially unlimited/unknown storage of a dictionary.

Chris
  • 27,210
  • 6
  • 71
  • 92
0

Dictionary is clearly the quickest solution.

Another way could be to store a custom class in which you could store the actual value and the information regarding its type

il_guru
  • 8,383
  • 2
  • 42
  • 51