How to initialize KeyValuePair object the proper way?
C#InitializationC# Problem Overview
I've seen in (amongst others) this question that people wonder how to initialize an instance of KeyValuePair, which expectedly should look like this.
KeyValuePair<int, int> keyValuePair = new KeyValuePair<int, int>
{
Key = 1,
Value = 2
};
It doesn't work, as if the properties aren't there. Intead, I need to use the constructor like this.
KeyValuePair<int, int> keyValuePair = new KeyValuePair<int, int>(1, 2);
Admittedly shorter syntax but it bothers me that I can't use the initializer. What am I doing wrong?
C# Solutions
Solution 1 - C#
You are not wrong you have to initialise a keyValuePair using
KeyValuePair<int, int> keyValuePair = new KeyValuePair<int, int>(1, 2);
The reason that you cannot use the object initialisation syntax ie { Key = 1, Value = 2 } is because the Key and Value properties have no setters only getters (they are readonly). So you cannot even do:
keyValuePair.Value = 1; // not allowed
Solution 2 - C#
Dictionaries have compact initializers:
var imgFormats = new Dictionary<string, ChartImageFormat>()
{
{".bmp", ChartImageFormat.Bmp},
{".gif", ChartImageFormat.Gif},
{".jpg", ChartImageFormat.Jpeg},
{".jpeg", ChartImageFormat.Jpeg},
{".png", ChartImageFormat.Png},
{".tiff", ChartImageFormat.Tiff},
};
In this case the dictionary i used to associate file extensions with image format constants of chart objects.
A single keyvaluepair can be returned from the dictionary like this:
var pair = imgFormats.First(p => p.Key == ".jpg");
Solution 3 - C#
KeyValuePair<int, int>
is a struct, and, fortunately, it is immutable struct. In particular, this means that its properties are read only. So, you can't use object intializer for them.
Solution 4 - C#
Ok you have the answers. As an alternative, I prefer factory pattern similar to Tuple
class, for type inference magic :)
public static class KeyValuePair
{
public static KeyValuePair<K, V> Create<K, V>(K key, V value)
{
return new KeyValuePair<K, V>(key, value);
}
}
So short becomes shorter:
var keyValuePair = KeyValuePair.Create(1, 2);
Solution 5 - C#
Here goes an example that does the job
KeyValuePair<int, int> kvp = new KeyValuePair<int, int>(1, 1);
Solution 6 - C#
The Key and Value properties have no setters. Thats why you can't use them in the initializer. Just use the constructor :) and you'll be fine.
Solution 7 - C#
I also prefer factory pattern. But I found this way much more to be more useful when I had to create a pair outside. This way I can support any simple to complex use case.
This way I could use any Type and make KeyValue Pairs from its properties or any predicate I want, But cleaner. Like the way similar to IEnumerable.ToDictionary(keySelector,valueSelector)
public static KeyValuePair<TKey, TValue> CreatePair<TSource, TKey, TValue>(
this TSource source,
Func<TSource, TKey> keySelector,
Func<TSource, TValue> valueSelector)
{
if (source is null)
{
throw new ArgumentNullException(nameof(source));
}
if (keySelector is null)
{
throw new ArgumentNullException(nameof(keySelector));
}
if (valueSelector is null)
{
throw new ArgumentNullException(nameof(valueSelector));
}
return new KeyValuePair<TKey, TValue>(
keySelector.Invoke(source),
valueSelector.Invoke(source));
}
And you use.
yourObject.CreatePair(
x=> x.yourKeyPropery,
x=> SomeOperationOnYourProperty(x.yourValueProperty));
Solution 8 - C#
The Key and Value properties are read-only, therefore you can't use them in an object initializer.
See this entry in the C# programming guide.
Solution 9 - C#
You aren't doing something wrong. The KeyValuePairs properties are read-only. You cannot set them. Additionally, there is no empty default constructor. You need to use the constructor provided.