How to initialize KeyValuePair object the proper way?

C#Initialization

C# 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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser1672517View Question on Stackoverflow
Solution 1 - C#Kevin HolditchView Answer on Stackoverflow
Solution 2 - C#flodisView Answer on Stackoverflow
Solution 3 - C#DennisView Answer on Stackoverflow
Solution 4 - C#nawfalView Answer on Stackoverflow
Solution 5 - C#Paulo CarvalhoView Answer on Stackoverflow
Solution 6 - C#Mihail ShishkovView Answer on Stackoverflow
Solution 7 - C#Jins PeterView Answer on Stackoverflow
Solution 8 - C#PhilView Answer on Stackoverflow
Solution 9 - C#nvoigtView Answer on Stackoverflow