Dictionary with a limited number of types

First off, excuse the rather funny name of my question. I am not a native speaker and it took me 10 minutes to express my thoughts in these few characters.

What I'm trying to do is create a C # dictionary that allows you to use a value like int , string or bool . At first, it occurred to me to use generics, but as far as I know, I can only define one type as a possible type of value, and not "be one of those." Using object also be possible, but boxing seems to be quite a performance killer.

Is there any way to do this?

Here is an example of what occurred to me:

 Dictionary<string, (string, int, bool)> foo = new Dictionary<string, (string, int, bool)>(); foo.Add("key1", "Hello, World!"); //Correct - Value is a string foo.Add("key2", 37); //Correct - Value is an int foo.Add("key3", true); //Correct - Value is a boolean foo.Add("key4", new Foobar()); //Compiler error - Value is a Foobar 

My ultimate goal is to provide a library for other developers. This function should allow them to define "variables" at run time and give them a type.

Edit: // Firefox 'about: config page has something very close to what I want to achieve

+6
source share
4 answers

Why not create a new new class that implements IDictionary and uses the dictionary as a private variable.

Then in the add methods you can provide your own logic and accordingly not execute

Code example

 public class MyDic : IDictionary<object, object> { private Dictionary<object, object> privateDic= new Dictionary<object,object>(); public void Add(object key, object value) { if (value.GetType() == typeof(string)) throw new ArgumentException(); privateDic.Add(key, value); } //Rest of the interface follows } 
+6
source

I would suggest:

  • Create a base type for dictionary values, for example. MyDictionaryBaseType
  • Extend this base type for each type of dictionary you have, for example. StringDictionryType: MyDictionaryBaseType, IntegerDictionryType: MyDictionaryBaseType ... etc.
  • Create a generic dictionary type with MyDictionaryBaseType and restrict the type to extend this base type.

Thus, you limit your literature to three predefined types.

0
source

You can put values ​​in wrapper classes as follows:

 class Value { } class TypedValue<T> : Value { public T Val; } class IntValue : TypedValue<int> { } class StringValue : TypedValue<string> { } class BoolValue : TypedValue<bool> { } Dictionary<string,Value> foo; foo.Add("key1", new StringValue{Val="Hello World!"}); 

Another possibility is to use a dictionary and perform a runtime check to add the correct or incorrect types. I don’t think there is a solution without boxing.

0
source

What you are trying to do is not type safe. For example, let's say you have a dictionary like this:

 var foo = new Dictionary<string, (string, int, bool)>(); var x = foo["key1"]; // What type is x? How could the compiler know? 

One idea would be to develop a container class that can contain one or a string , int or bool .

 public class StringIntBool { private bool _isSet; private bool _isString; public bool IsString { get { return _isString; } } // ... private string _innerString; public string InnerString { get { return _innerString; } set { if (_isSet) { throw new Exception("StringIntBool is already set"); } _isSet = true; _isString = true; _innerString = value; } } // etc... } 

This is pretty ugly and doesn't really provide many benefits.

Alternatively, you could save all three values ​​as object s, and then use a technique / library like Functional C # to perform pattern matching, as many functional languages ​​can.

 object x = "str"; int res = x.Match() .With<string>(s => s == "str" ? 10 : 20) .With<int>(i => i) .With<bool>(b => b ? 50 : 60) .Return<int>(); 

This programming scheme is actually quite common in a specific functional language. For example, in SML, you can define a data type and then map it to a template as needed.

 (* StringIntBool *) datatype sib = SibString of string | SibInt of int | SibBool of bool val x = (* some instance of sib *) val y = case x of SibString s => if s = "hello" then 50 else -50 | SibInt i => i | SibBool b => if b then 10 else 20 
0
source

All Articles