I would like to write something like this:
var d = new ImmutableDictionary<string, int> { { "a", 1 }, { "b", 2 } };
(using ImmutableDictionary from System.Collections.Immutable). It seems like a straightforward usage as I am declaring all the values upfront -- no mutation there. But this gives me error:
The type 'System.Collections.Immutable.ImmutableDictionary<TKey,TValue>' has no constructors defined
How I am supposed to create a new immutable dictionary with static content?
You can't create immutable collection with a collection initializer because the compiler translates them into a sequence of calls to the Add method. For example if you look at the IL code for var d = new Dictionary<string, int> { { "a", 1 }, { "b", 2 } }; you'll get
IL_0000: newobj instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::.ctor()
IL_0005: dup
IL_0006: ldstr "a"
IL_000b: ldc.i4.1
IL_000c: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0, !1)
IL_0011: dup
IL_0012: ldstr "b"
IL_0017: ldc.i4.2
IL_0018: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0, !1)
Obviously this violates the concept of immutable collections.
Both your own answer and Jon Skeet's are ways to deal with this.
// lukasLansky's solution
var d = new Dictionary<string, int> { { "a", 1 }, { "b", 2 } }.ToImmutableDictionary();
// Jon Skeet's solution
var builder = ImmutableDictionary.CreateBuilder<string, int>();
builder.Add("a", 1);
builder.Add("b", 2);
var result = builder.ToImmutable();
Either create a "normal" dictionary first and call ToImmutableDictionary (as per your own answer), or use ImmutableDictionary<,>.Builder:
var builder = ImmutableDictionary.CreateBuilder<string, int>();
builder.Add("a", 1);
builder.Add("b", 2);
var result = builder.ToImmutable();
It's a shame that the builder doesn't have a public constructor as far as I can tell, as it prevents you from using the collection initializer syntax, unless I've missed something... the fact that the Add method returns void means you can't even chain calls to it, making it more annoying - as far as I can see, you basically can't use a builder to create an immutable dictionary in a single expression, which is very frustrating :(
So far I like this most:
var d = new Dictionary<string, int> { { "a", 1 }, { "b", 2 } }.ToImmutableDictionary();
You could use a helper like this:
public struct MyDictionaryBuilder<TKey, TValue> : IEnumerable
{
private ImmutableDictionary<TKey, TValue>.Builder _builder;
public MyDictionaryBuilder(int dummy)
{
_builder = ImmutableDictionary.CreateBuilder<TKey, TValue>();
}
public void Add(TKey key, TValue value) => _builder.Add(key, value);
public TValue this[TKey key]
{
set { _builder[key] = value; }
}
public ImmutableDictionary<TKey, TValue> ToImmutable() => _builder.ToImmutable();
public IEnumerator GetEnumerator()
{
// Only implementing IEnumerable because collection initializer
// syntax is unavailable if you don't.
throw new NotImplementedException();
}
}
(I'm using the new C# 6 expression-bodied members, so if you want this to compile on older versions, you'd need to expand those into full members.)
With that type in place, you can use collection initializer syntax like so:
var d = new MyDictionaryBuilder<int, string>(0)
{
{ 1, "One" },
{ 2, "Two" },
{ 3, "Three" }
}.ToImmutable();
or if you're using C# 6 you could use object initializer syntax, with its new support for indexers (which is why I included a write-only indexer in my type):
var d2 = new MyDictionaryBuilder<int, string>(0)
{
[1] = "One",
[2] = "Two",
[3] = "Three"
}.ToImmutable();
This combines the benefits of both proposed advantages:
Avoids building a full Dictionary<TKey, TValue>
Lets you use initializers
The problem with building a full Dictionary<TKey, TValue> is that there is a bunch of overhead involved in constructing that; it's an unnecessarily expensive way of passing what's basically a list of key/value pairs, because it will carefully set up a hash table structure to enable efficient lookups that you'll never actually use. (The object you'll be performing lookups on is the immutable dictionary you eventually end up with, not the mutable dictionary you're using during initialization.)
ToImmutableDictionary is just going to iterate through the contents of the dictionary (a process rendered less efficient by the way Dictionary<TKey, TValue> works internally - it takes more work to do this than it would with a simple list), gaining absolutely no benefit from the work that went into building up the dictionary, and then has to do the same work it would have done if you'd used the builder directly.
Jon's code avoids this, using only the builder, which should be more efficient. But his approach doesn't let you use initializers.
I share Jon's frustration that the immutable collections don't provide a way to do this out of the box.
Edited 2017/08/10: I've had to change the zero-argument constructor to one that takes an argument that it ignores, and to pass a dummy value everywhere you use this. #gareth-latty pointed out in a comment that a struct can't have a zero-args constructor. When I originally wrote this example that wasn't true: for a while, previews of C# 6 allowed you to supply such a constructor. This feature was removed before C# 6 shipped (after I wrote the original answer, obviously), presumably because it was confusing - there were scenarios in which the constructor wouldn't run. In this particular case it was safe to use it, but unfortunately the language feature no longer exists. Gareth's suggestion was to change it into a class, but then any code using this would have to allocate an object, causing unnecessary GC pressure - the whole reason I used a struct was to make it possible to use this syntax with no additional runtime overhead.
I tried modifying this to perform deferred initialization of _builder but it turns out that the JIT code generator isn't smart enough to optimize these away, so even in release builds it checks _builder for each item you add. (And it inlines that check and the corresponding call to CreateBuilder which turns out to produce quite a lot of code with lots of conditional branching). It really is best to have a one-time initialization, and this has to occur in the constructor if you want to be able to use this initializer syntax. So the only way to use this syntax with no additional costs is to have a struct that initializes _builder in its constructor, meaning that we now need this ugly dummy argument.
Or this
ImmutableDictionary<string, int>.Empty
.Add("a", 1)
.Add("b", 2);
There is also AddRange method available.
I prefer this syntax:
var dict = ImmutableDictionaryEx.Create<int, string>(
(1, "one"),
(2, "two"),
(3, "three"));
Can be easily achieved using this method:
public static class ImmutableDictionaryEx {
/// <summary>
/// Creates a new <see cref="ImmutableDictionary"/> with the given key/value pairs.
/// </summary>
public static ImmutableDictionary<K, V> Create<K, V>(params (K key, V value)[] items) where K : notnull {
var builder = ImmutableDictionary.CreateBuilder<K, V>();
foreach (var (key, value) in items)
builder.Add(key, value);
return builder.ToImmutable();
}
}
There is another answer I don't see here (maybe it's a new method?):
Just use the CreateRange method to create a new ImmutableDictionary using an IEnumerable<KVP>.
// The MyObject record example
record MyObject(string Name, string OtherStuff);
// The init logic for the ImmutableDictionary
var myObjects = new List<MyObject>();
var dictionary = ImmutableDictionary
.CreateRange(myObjects.Select(obj => new KeyValuePair<string, MyObject>(obj.Name, obj)));
You could write a custom ImmutableDictionaryLiteral class with an implicit operator to make a syntax very close to what you want.
public class ImmutableDictionaryLiteral<TKey, TValue> : Dictionary<TKey, TValue>
{
public static implicit operator ImmutableDictionary<TKey, TValue>(ImmutableDictionaryLiteral<TKey, TValue> source)
{
return source.ToImmutableDictionary();
}
}
Then you call it by declaring a ImmutableDictionary<TKey, TValue> variable and initializing with a ImmutableDictionaryLiteral<TKey, TValue> value.
ImmutableDictionary<string, string> dict = new ImmutableDictionaryLiteral<string, string>()
{
{ "key", "value" },
{ "key2", "value2" }
};
This also works with object initializer syntax
ImmutableDictionary<string, string> dict = new ImmutableDictionaryLiteral<string, string>()
{
["key"] = "value",
["key2"] = "value2"
};
Related
I am trying to give out a IReadOnly-references to internal Collection objects.
This works well in most cases, but does not if i want to convert a dictionary containing a collection into an IReadOnlyDictionary containing a IReadOnlyCollection.
Here a code example:
var list = new List<int>();
IReadOnlyList<int> listReference = list; //works;
var dictionary = new Dictionary<int, int>();
IReadOnlyDictionary<int, int> dictionaryReference = dictionary; //works
var nestedList = new List<List<int>>();
IReadOnlyList<IReadOnlyList<int>> nestedReadOnlyListReference = nestedList; //works
var nestedDictionary = new Dictionary<int, List<int>>();
//IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary; //does not work, can not implicitly convert
//current workaround
var nestedDictionaryReferenceHelper = new Dictionary<int, IReadOnlyList<int>>();
foreach (var kvpNestedDictionary in nestedDictionary)
{
nestedDictionaryReferenceHelper.Add(kvpNestedDictionary.Key, (IReadOnlyList<int>)kvpNestedDictionary.Value);
}
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionaryReferenceHelper; //works, but is only a reference to the internal List, not to the dictionary itself
The workaround is pretty ugly as it needs additional memory and needs manual updating every time the values of nestedDictionary change.
Is there any simple way to convert such nested dictionaries?
In this SO question you can find a very good explanation why casting dictionary values is not supported. Please see the accepted answer of Eric Lippert.
Although i would not recommend this, you could use the following LINQ expression to cast the values of the dictionary to a read only list:
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary.ToDictionary(kv => kv.Key, kv => kv.Value as IReadOnlyList<int>);
It is a shorter version of your workaround and it is lazy evaluated, but i would not recommend this due to the following reasons:
This solution still creates a copy of the dictionary and does not update any new/deleted entries from the original dictionary.
The values of the dictionary, i.e. the readonly lists, refer to the original lists and changes there are updated in the read only versions in the dictionary too.
This is inconsistent behavior and therefore a bad practice!
Unless it is not possible to cast the values of a dictionary, i would not recommend doing this. You should either deep copy the entire dictionary including the nested lists, or use an other container that supports casting.
In my opinion the point is the you're missing the opportunity to introduce a proper new type with its own dignity. If you're using Dictionary<int, List<int>> then you will see yourself with code like this every time you need to insert a value:
if (!_dictionary.ContainsKey(key)) {
var list = new List<int>();
list.Add(value);
_dictionary.Add(key, list);
} else {
_dictionary[key].Add(value);
}
And even worse with code like this when you want to search for a value:
_dictionary.ContainsKey(key) && _dictionary[key].Contains(value);
And variation of those examples. What's worse you're exposing this implementation detail to your class users. If this detail will change then you will break all code. What, for example, if you want to replace List<int> with HashSet<int>?
How it should be?
_multimap.Add(key, value);
With a proper interface (here I show just few methods):
public interface IMultiMap<TKey, TValue> {
void Add(TKey key, TValue value);
bool ContainsKey(TKey key);
}
And its implementation:
public sealed class MultiMap<TKey, TValue> : IMultiMap<TKey, TValue> {
// ...
private Dictionary<int, List<int>> _items;
}
You can introduce IReadOnlyMultiMap<TKey, TValue>:
public interface IReadOnlyMultiMap<TKey, TValue> {
bool ContainsKey(TKey key);
}
Just implement IReadOnlyMultiMap<TKey, TValue> in MultiMap<TKey, TValue> and to return a read-only collection you have nothing to do (fictional example):
IReadOnlyMultiMap<int, int> MakeReadOnly(MultiMap<int, int> map) {
return map; // Nothing to do!
}
Note that you may want to introduce a new ReadOnlyMultiMap<TKey, TValue> to tunnel read calls to underlying live collection (to avoid callers to simply cast to MultiMap<TKey, TValue> to circumvent read-only limitation). Proof of concept:
public sealed class ReadOnlyMultiMap<TKey, TValue> : IReadOnlyMultiMap<TKey, TValue> {
public ReadOnlyMultiMap(IMultiMap<TKey, TValue> collection) {
_collection = collection;
}
public bool ContainsKey(TKey key) {
return _collection.ContainsKey(key);
}
private readonly IMultiMap<TKey, TValue> _collection;
}
To return a read-only view you do:
IReadOnlyMultiMap<int, int> MakeReadOnly(MultiMap<int, int> map) {
return new ReadOnlyMultiMap<int, int>(map);
}
Note that I talked about implementation detail. You're still exposing an implementation detail (you're using a multimap) then if such code is for a public API you should introduce a new (properly named) type to describe what it contains, not how storage is implemented. It may be MeasureCollection, SoccerScoreCollection or whatever your model is talking about, storage may vary but content won't.
Problem for conversion failing is the KeyValuePair:
Although class Derived inheriting class Base, KeyValuePair is not a sub class of KeyValuePair; see definitions(Dictionary, IReadOnlyDictionary).
So you always will need some kind of workaround (MultiMap approach appears to me as one, too...). If nestedDictionary is private, so you have complete control over it from your class, you might get away with this:
var nestedDictionary = new Dictionary<int, IReadOnlyList<int>>();
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary;
and whenever modifying a list within the dictionary applying a cast to List<int>. Another ugly workaround, I admit, but saves you extra memory and redundancy management and retains the (asumed...) public interface of IReadOnlyDictionary<int, IReadOnlyList<int>>.
Edit: just an idea, haven't tested, but it might work: Have your own dictionary adding the missing interfaces to be assignable to the read-only dictionary:
public class MyDictionary
: Dictionary<int, List<int>>,
ICollection<KeyValuePair<int, IReadOnlyList<int>>,
IEnumerable<KeyValuePair<int, IReadOnlyList<int>>,
IReadOnlyCollection<KeyValuePair<int, IReadOnlyList<int>>
{
}
I might yet have missed an interface to be implemented, and you might have to implement some members yet. If it works, possibly the cleanest solution...
Collections like HashTable and Dictionary don't allow to add a value with the same key but I want to store the same values with the same keys in a Collection<int,string>.
Is there a built-in collection which lets me do this?
You can use a List<T> containing a custom class, or even a List<Tuple<int,string>>.
List<Tuple<int,string>> values = new List<Tuple<int,string>>();
values.Add(Tuple.Create(23, "Foo"));
values.Add(Tuple.Create(23, "Bar"));
Alternatively, you can make a Dictionary<int, List<string>> (or some other collection of string), and populate the values in that way.
Dictionary<int, List<string>> dict = new Dictionary<int, List<string>>();
dict.Add(23, new List<string> { "Foo", "Bar" });
This has the advantage of still providing fast lookups by key, while allowing multiple values per key. However, it's a bit trickier to add values later. If using this, I'd encapsulate the adding of values in a method, ie:
void Add(int key, string value)
{
List<string> values;
if (!dict.TryGetValue(key, out values))
{
values = new List<string>();
dict[key] = values;
}
values.Add(value);
}
Use a List with a custom Class.
public class MyClass
{
public int MyInt { get; set; }
public string MyString { get; set; }
}
List<MyClass> myList = new List<MyClass>();
myList.Add(new MyClass { MyInt = 1, MyString = "string" });
In short: The easiest way to go would be a generic List<T> collection while skiping the ArrayList class. Because, there are some performance considerations that you need to take into account.
In addition, you can also use List<KeyValuePair<string,int>>.
This will store a list of KeyValuePair 's that can be duplicate.
In deciding whether to use the List<T> or ArrayList class, both of which have similar functionality, remember that the List<T> class performs better in most cases and is type safe. If a reference type is used for type T of the List<T> class, the behavior of the two classes is identical. However, if a value type is used for type T, you need to consider implementation and boxing issues.
As reference: you may use the following MSDN article - List Class.
Today I was surprised to find that in C# I can do:
List<int> a = new List<int> { 1, 2, 3 };
Why can I do this? What constructor is called? How can I do this with my own classes? I know that this is the way to initialize arrays but arrays are language items and Lists are simple objects ...
This is part of the collection initializer syntax in .NET. You can use this syntax on any collection you create as long as:
It implements IEnumerable (preferably IEnumerable<T>)
It has a method named Add(...)
What happens is the default constructor is called, and then Add(...) is called for each member of the initializer.
Thus, these two blocks are roughly identical:
List<int> a = new List<int> { 1, 2, 3 };
And
List<int> temp = new List<int>();
temp.Add(1);
temp.Add(2);
temp.Add(3);
List<int> a = temp;
You can call an alternate constructor if you want, for example to prevent over-sizing the List<T> during growing, etc:
// Notice, calls the List constructor that takes an int arg
// for initial capacity, then Add()'s three items.
List<int> a = new List<int>(3) { 1, 2, 3, }
Note that the Add() method need not take a single item, for example the Add() method for Dictionary<TKey, TValue> takes two items:
var grades = new Dictionary<string, int>
{
{ "Suzy", 100 },
{ "David", 98 },
{ "Karen", 73 }
};
Is roughly identical to:
var temp = new Dictionary<string, int>();
temp.Add("Suzy", 100);
temp.Add("David", 98);
temp.Add("Karen", 73);
var grades = temp;
So, to add this to your own class, all you need do, as mentioned, is implement IEnumerable (again, preferably IEnumerable<T>) and create one or more Add() methods:
public class SomeCollection<T> : IEnumerable<T>
{
// implement Add() methods appropriate for your collection
public void Add(T item)
{
// your add logic
}
// implement your enumerators for IEnumerable<T> (and IEnumerable)
public IEnumerator<T> GetEnumerator()
{
// your implementation
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Then you can use it just like the BCL collections do:
public class MyProgram
{
private SomeCollection<int> _myCollection = new SomeCollection<int> { 13, 5, 7 };
// ...
}
(For more information, see the MSDN)
It is so called syntactic sugar.
List<T> is the "simple" class, but compiler gives a special treatment to it in order to make your life easier.
This one is so called collection initializer. You need to implement IEnumerable<T> and Add method.
According to the C# Version 3.0 Specification "The collection object to which a collection initializer is applied must be of a type that implements System.Collections.Generic.ICollection for exactly one T."
However, this information appears to be inaccurate as of this writing; see Eric Lippert's clarification in the comments below.
It works thanks to collection initializers which basically require the collection to implement an Add method and that will do the work for you.
Another cool thing about collection initializers is that you can have multiple overloads of Add method and you can call them all in the same initializer! For example this works:
public class MyCollection<T> : IEnumerable<T>
{
public void Add(T item, int number)
{
}
public void Add(T item, string text)
{
}
public bool Add(T item) //return type could be anything
{
}
}
var myCollection = new MyCollection<bool>
{
true,
{ false, 0 },
{ true, "" },
false
};
It calls the correct overloads. Also, it looks for just the method with name Add, the return type could be anything.
The array like syntax is being turned in a series of Add() calls.
To see this in a much more interesting example, consider the following code in which I do two interesting things that sound first illegal in C#, 1) setting a readonly property, 2) setting a list with a array like initializer.
public class MyClass
{
public MyClass()
{
_list = new List<string>();
}
private IList<string> _list;
public IList<string> MyList
{
get
{
return _list;
}
}
}
//In some other method
var sample = new MyClass
{
MyList = {"a", "b"}
};
This code will work perfectly, although 1) MyList is readonly and 2) I set a list with array initializer.
The reason why this works, is because in code that is part of an object intializer the compiler always turns any {} like syntax to a series of Add() calls which are perfectly legal even on a readonly field.
I'm a former C++/STL programmer trying to code a fast marching algorithm using C#/.NET technology...
I'm searching for an equivalent of STL method map::insert that insert a value at given key if not exists, else returns an iterator to the existing key-value pair.
The only way I found does this with two lookups: one inside TryGetValue and another one in Add method:
List<Point> list;
if (!_dictionary.TryGetValue (pcost, out list))
{
list = new List<Point>();
dictionary.Add (pcost, list);
}
list.Add(new Point { X = n.x, Y = n.y });
Is there something that explains why this is not possible using .NET containers? Or did I missed some point?
You can just assign your value in the following way:
var dict = new Dictionary<int, int>();
dict[2] = 11;
if value with key 2 does not exist - it will be added and otherwise it will be just overriden.
Dictionary does not have method GetOrAdd, but ConcurrentDictionary from C# 4.0 does:
var dict = new ConcurrentDictionary<int, int>();
dict[2] = 10;
int a = dict.GetOrAdd(2, 11);// a == 10
The standard generic dictionary does not support this, the 2 lookups are required. Though the cost of the look ups are normally negligible so this isn't a problem, and you can often get better results tuning other parts of the system rather than trying to micro-optimise dictionary lookups.
The only dictionary that comes with .net that supports this that I know of is ConcurrentDictionary with the method GetOrAdd. Though now you're paying the cost of synchronization instead.
Is there something that explains why
this is not possible using .NET
containers ?
Without knowing the real background, I assume it is because of simplicity of the Dictionary. There are only the basic, easy to understand functions: Add, Remove a.s.o., while the index operator does a little bit of magic, which was probably assumed to be intuitive.
Sadly, there isn't one in bcl's implementation. The closest alternative is doing two lookups, but one can have a generic extension method to make it easy, as shown here
public static T GetOrAdd<S, T>(this IDictionary<S, T> dict, S key,
Func<T> valueCreator)
{
T value;
return dict.TryGetValue(key, out value) ? value : dict[key] = valueCreator();
}
But there is C5's implementation which does this out of the box. The method definition looks like this:
public virtual bool FindOrAdd(K key, ref V value)
{
}
I don't know why they don't accept a Func<V> instead of V to defer object creation. C5 has a lot of nice similar tricks, for eg,
public virtual bool Remove(K key, out V value)
public virtual bool Update(K key, V value, out V oldvalue)
public virtual bool UpdateOrAdd(K key, V value, out V oldvalue)
Starting from .NET 6, it is now possible to implement a GetOrAdd extension method for the Dictionary<TKey, TValue> class that takes a key and a valueFactory, and hashes the key only once. The new API is the CollectionsMarshal.GetValueRefOrAddDefault method, with this signature:
// Gets a reference to a TValue in the specified dictionary, adding a new entry
// with a default value if the key does not exist.
public static ref TValue? GetValueRefOrAddDefault<TKey,TValue> (
Dictionary<TKey,TValue> dictionary, TKey key, out bool exists);
This is a ref returning method. It can be used to implement the GetOrAdd like this:
/// <summary>
/// Adds a key/value pair to the dictionary by using the specified function
/// if the key does not already exist. Returns the new value, or the
/// existing value if the key exists.
/// </summary>
public static TValue GetOrAdd<TKey, TValue>(
this Dictionary<TKey, TValue> dictionary,
TKey key,
Func<TKey, TValue> valueFactory)
{
ArgumentNullException.ThrowIfNull(dictionary);
ArgumentNullException.ThrowIfNull(valueFactory);
ref TValue value = ref CollectionsMarshal
.GetValueRefOrAddDefault(dictionary, key, out bool exists);
if (!exists)
{
try { value = valueFactory(key); }
catch { dictionary.Remove(key); throw; }
}
return value;
}
Usage example:
List<Point> list = dictionary.GetOrAdd(pcost, key => new List<Point>());
list.Add(new Point { X = n.x, Y = n.y });
Online demo, featuring also an overload with generic parameter TArg.
The try/catch in the implementation is required in order to remove the empty entry, in case the valueFactory throws an exception. Otherwise the exception would leave the dictionary in a corrupted state (containing a key with a default value).
Btw a proposal to add this method in the standard .NET libraries has been submitted on GitHub, but it didn't generate enough traction and it was closed.
Old question, but I may have just stumbled across an acceptable solution. I use a combination of TryGetValue, ternary operator and index assignment.
var thing = _dictionary.TryGetValue(key, out var existing) ? existing : _dictionary[key] = new Thing();
I have written a small example for that.
class Program
{
private static readonly Dictionary<string, string> _translations
= new Dictionary<string, string>() { { "en", "Hello world!" } };
private static string AddOrGetTranslation(string locale, string defaultText)
=> _translations.TryGetValue(locale, out var existingTranslation)
? existingTranslation
: _translations[locale] = defaultText;
static void Main()
{
var defaultText = "#hello world#";
Console.WriteLine(AddOrGetTranslation("en", defaultText)); // -> Hello world!
Console.WriteLine(AddOrGetTranslation("de", defaultText)); // -> #hello world#
Console.WriteLine(AddOrGetTranslation("de", "differentDefaultText")); // -> #hello world#
_translations["de"] = "Hallo Welt!";
Console.WriteLine(AddOrGetTranslation("de", defaultText)); // -> Hallo Welt!
}
}
EDIT: ⚠️ There is an uncertainty of this solution. See comments on the solution.
You can create extension method for that:
IDictionary<string, Point> _dictionary = GetDictionary();
_dictionary.GetOrAdd( "asdf" ).Add( new Point(14, 15) );
// ... elsewhere ...
public static class DictionaryExtensions {
public static List<TValue> GetOrAdd<TKey, TValue>( this IDictionary<TKey, List<TValue>> self, TKey key ) {
List<TValue> result;
self.TryGetValue( key, out result );
if ( null == result ) {
// the key value can be set to the null
result = new List<TValue>();
self[key] = result;
}
return result;
}
}
Simple. If I use:
public void Add(params int[] values)
Then I can use this as:
Add(1, 2, 3, 4);
But now I'm dealing with key-value pairs! I have a KeyValue class to link an integer to a string value. So I start with:
public void Add(params KeyValue[] values)
But I can't use this:
Add(1, "A", 2, "B", 3, "C", 4, "D");
Instead, I'm forced to use:
Add(new KeyValue(1, "A"), new KeyValue(2, "B"), new KeyValue(3, "C"), new KeyValue(4, "D"));
Ewww... Already I dislike this...
So, right now I use the Add function without the params modifier and just pass a pre-defined array to this function. Since it's just used for a quick initialization for a test, I'm not too much troubled about needing this additional code, although I want to keep the code simple to read. I would love to know a trick to use the method I can't use but is there any way to do this without using the "new KeyValue()" construction?
If you accepted an IDictionary<int,string>, you could presumably use (in C# 3.0, at least):
Add(new Dictionary<int,string> {
{1, "A"}, {2, "B"}, {3, "C"}, {4, "D"}
});
Any use?
Example Add:
static void Add(IDictionary<int, string> data) {
foreach (var pair in data) {
Console.WriteLine(pair.Key + " = " + pair.Value);
}
}
You can modify your current class design, but you will need to add generics and use the IEnumerable interface.
class KeyValue<TKey, TValue>
{
public KeyValue()
{
}
}
// 1. change: need to implement IEnumerable interface
class KeyValueList<TKey, TValue> : IEnumerable<TKey>
{
// 2. prerequisite: parameterless constructor needed
public KeyValueList()
{
// ...
}
// 3. need Add method to take advantage of
// so called "collection initializers"
public void Add(TKey key, TValue value)
{
// here you will need to initalize the
// KeyValue object and add it
}
// need to implement IEnumerable<TKey> here!
}
After these additions you can do the following:
new KeyValueList<int, string>() { { 1, "A" }, { 2, "B" } };
The compiler will use the IEnumerable interface and the Add method to populate the KeyValueList. Note that it works for C# 3.0.
If you are using this for tests, these changes are not worth it. It's quite an effort and you change quite a lot of production code for tests.
You could use something like the following with the obvious drawback that you loose strong typing.
public void Add(params Object[] inputs)
{
Int32 numberPairs = inputs.Length / 2;
KeyValue[] keyValues = new KeyValue[numberPairs];
for (Int32 i = 0; i < numberPairs; i++)
{
Int32 key = (Int32)inputs[2 * i];
String value = (String)inputs[2 * i + 1];
keyvalues[i] = new KeyValue(key, value);
}
// Call the overloaded method accepting KeyValue[].
this.Add(keyValues);
}
public void Add(params KeyValue[] values)
{
// Do work here.
}
You should of cause add some error handling if the arguments are of incorrect type. Not that smart, but it will work.