Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add element to dictionary where key is property of value

Tags:

c#

dictionary

I am trying to build a dictionary where the key is a property of the value object. However I would like to construct the value object in the dictionary's add method. Is there a way to do this without using an intermediate variable?

For example I would like to do the following, but of course the key value isn't available when needed.

Dictionary<int,SomeComplexObject> dict = new Dicionary<int,SomeComplexObject>{
   {someComplexObject.Key, new SomeComplexObject {Key = 1, Name = "FooBar"},
   {someComplexObject.Key, new SomeComplexObject {Key = 2, Name = "FizzBang"} 
};

Do I have to do it this ugly way:

Dictionary<int,SomeComplexObject> dict = new Dicionary<int,SomeComplexObject>();
SomeComplexObject value1 = new SomeComplexObject{Key=1,Name = "FooBar"};
dict.Add(value1.Key,value1);
SomeComplexObject value2 = new SomeComplexObject{Key=2,Name = "FizzBang"};
dict.Add(value.Key,value2);

I don't think this is the same question as How to use an object's identity as key for Dictionary<K,V>

because I am not asking specifically about the key of a dictionary but if there is a way to have access to a objects property when the object is not being created until later in the methods parameter list.

like image 396
automatic Avatar asked Feb 16 '17 17:02

automatic


People also ask

How to assign a value to a key in Python Dictionary?

Python add to Dictionary using “=” assignment operator If you want to add a new key to the dictionary, then you can use the assignment operator with the dictionary key. This is pretty much the same as assigning a new value to the dictionary.

Can we add duplicate keys in Dictionary C#?

The Key value of a Dictionary is unique and doesn't let you add a duplicate key entry.

Can a Dictionary be a property C#?

Item[] Property. This property is used to get or set the value associated with the specified key in the Dictionary. Here, key is the Key of the value to get or set.

How do you add to a Dictionary in C#?

Add() Method is used to add a specified key and value to the dictionary. Syntax: public void Add (TKey key, TValue value);


2 Answers

I don't think an extension method (as proposed in comments) is really what you want here, as it's only a partial solution. I.e. you would have to write a new extension method for each dictionary value type you wanted to use, which negates the whole point of asking for a general solution.

Instead, it seems to me that you probably just want to subclass the Dictionary<TKey, TValue> type to add your own custom behavior. You can do this just once, in a general-purpose way, so that you can provide a delegate for each type you expect to have to use this way.

That would look something like this:

class KeyExtractorDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
    private readonly Func<TValue, TKey> _extractor;

    public KeyExtractorDictionary(Func<TValue, TKey> extractor)
    {
        _extractor = extractor;
    }

    public void Add(TValue value)
    {
        Add(_extractor(value), value);
    }
}

You would use it something like this:

class Data
{
    public int Key { get; }
    public string Name { get; }

    public Data(int key, string name)
    {
        Key = key;
        Name = name;
    }
}

class Program
{
    static void Main(string[] args)
    {
        KeyExtractorDictionary<int, Data> dictionary =
            new KeyExtractorDictionary<int, Data>(d => d.Key)
            {
                new Data(1, "FooBar"),
                new Data(2, "FizzBang")
            };
    }
}

(I used Data as the value type type, instead of T as you seem to have used in your question, to avoid confusing the type name with a generic type parameter.)

In this way, you only have to write the class once, regardless of how many different types you might want to use for this type of dictionary. You can then pass the class constructor the key extractor delegate appropriate for the current value type of the dictionary.

Note that doing it this way, you also can take advantage of C#'s collection initializer syntax. Since your new type has an Add() method that takes just the value for each dictionary entry, the compiler will translate a collection initializer into the correct calls to add each object to the dictionary.

This allows for a dictionary in which you can still retrieve objects solely by the key value (using a custom comparer would require an instance of the value type with the same key you're looking for), while still addressing the broader concerns of not having to specify the key explicitly when adding objects, and of generality and reuse.

like image 172
Peter Duniho Avatar answered Oct 04 '22 22:10

Peter Duniho


You can try an extension method, which is less invasive:

public static void AddByKey<TKey, T>(this Dictionary<TKey, T> dictionary, T item)
{
    dictionary.Add(item.Key, item);
}

But to really do this correctly you also need an interface to protect you against types without the Key property:

public interface ItemWithKey<TKey>
{
    TKey Key { get; }
}

public static void AddByKey<TKey, T>(this Dictionary<TKey, T> dictionary, T item)
    where T : ItemWithKey<TKey>
{
    dictionary.Add(item.Key, item);
}

I don't have a compiler in my hands right now, I cannot test this code so minor errors may have slipped in. I hope you get the idea and usefulness if you have those cases a lot in your code. Otherwise, I'd advise to go with the ugly working code you already have.

like image 28
pid Avatar answered Oct 04 '22 21:10

pid