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?
9 Answers 9
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
Comments
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");
Comments
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.
7 Comments
struct itself doesn't equal immutability.new Tuple<int, int> { Item1 = 1, Item2 = 2 } gives the exact same error (together with an error that no constructor overload for Tuple<,> takes 0 arguments).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);
1 Comment
Create has been a part of .NET (but not .NET Framework), so you do not have to write the method yourself anymore.Here goes an example that does the job
KeyValuePair<int, int> kvp = new KeyValuePair<int, int>(1, 1);
Comments
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.
Comments
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));
Comments
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.
Comments
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.
3 Comments
var test = new KeyValuePair<int, int>(); will still be OK. The reason is that KeyValuePair<,> is a struct. And for a struct, the default value (also called default(KeyValuePair<int, int>)) will be created if you use a new object expression with zero arguments. In this case, a pair where both key and value are default(int) which is zero.