Geek Culture
Published in

Geek Culture

Converting Dictionary to Generic List<T> With Custom Attribute

If you have some string key and object values in the dictionary and want to convert to the “List of <T>” model and need some specific operations for some properties, this article is for you.

In this article, we will take two different approaches. One of them is Dictionary Extension Class with Mapped Config file and the other is Better Performance Of Dictionary Extension Class.

Model/SentMail.cs: This is our converted Dictionary List<T> model. We will convert Dictionary key-value data to “List<SenMail>”. “MailType” is int Enum field. We will write a custom “[JsonData]” attribute and we will sign the Recipient property with this attribute. We will talk about this later in the article.

Not: “Konu”, is especially defined in Turkish. It means subject. We will map it with the “subject” keyword, by using config later.

CustomAttribute/JsonData.cs: This is our custom attribute. It is used for only flagging a property of a class. This property is a complex type of dictionary value. And we will convert it to the string when we see this flag.

StaticConverter/ToJson(): This extension is used for converting object to string.

Enums/MailType.cs: This is integer MailType property of SentMail.

Model/Email.cs: This is our complex type of “Recipient” keyword of dictionary value. We will convert this, List of Classes to a string for mapping the Recipient property of the “SentMail” class.

Enum/SenderType.cs: This is the Email class’s property SenderType. It is an integer Enum.

Program.cs(1): Firstly, let’s fill the ten thousand “SentMail” model into the dictionary by key and value. “Recipients” is the list of “Email”. We will set it to the “Recipient” field in the dictionary. “uniqueKey” is the ignore key. We will not save it to the DB. We used it, to not allow the duplicate row. (”if (dictList.Any(dic => dic[“uniqueKey”].ToString() == uniqueKey))”)

DictionaryToList<T> Extension (Version 1): The first approach, writing a static extension class. Next, we will add new features to this class.

1-) We will start a timer, for calculating the total time. We will create a generic List<T>, which we will fill and return it. We will loop every dictionary in the dictionary list.

2-)We will create, a generic “T” class by using reflection. We will loop every item in the dictionary. “uniqueKey” is ignore key. We can use it only for custom operations. For example, it could be used for checking whether the same record is existing or not. There is no matching column on DB for the “uniqueKey”. Every key is the name of the class’s property. We will get “PropertyInfo” with a string key by using reflection. We will get the “Type” of property. And the check is it null or not.

3-) As we talked about at the beginning of this article[JsonData] Recipient property of the SentMail” is string type. But in the Hash, we set Recipient as a complex type so we have to convert this field to a JSON string. We will check the “JsonData” custom attribute. If any property has this attribute, we will convert it to a string with the custom “ToJson()” extension. Later we will improve the performance for this part. And finally, we will set this property with the hash value.

4-) Finally, we will add the SendMail model to the List, write the total passed time and return the list.

Extensions/ToJson(): It is used for converting an object (class) to a string.

“Positive attitude plus effort equals performance.”

— Tommy Tuberville

Mapped Different fields name between Dictionary and Class

We will match dictionary “Subject” key with “Konu” property of SentMail class.

StaticConverter/CheckedMapedKey(): We will map the dictionary string key value and model property name with this method. We will send dictionary config values and find the match of the string key parameter with this method.

DictionaryToList<T> Extension (Version 2):

We will add the “Dictionary ColumnMatchTable” parameter to this extension. And mapped different string dictionary keys and class property names.

Example of Map Config Dictionary: We will match different column names with this method.

“Details make perfection, and perfection is not a detail.”

Leonardo Da Vinci

Improve The Performance:

1-) For every item in the dictionary, we don’t have to check the attributes of every property. Only checking attributes for the first item, is enough. “Attribute.IsDefined()” reflection method consumes a lot of resources. That’s why we should stay as far away as possible. So we will add “CheckAttribute()” static Method. It is used for checking the attribute of properties. And if it finds an attribute, it will add it to “AttributeDictionaryList” with its property name and attribute name.

2-) List<T> is our return model and “AttributeDictionaryList” is a list, which is used for storing attributes with model properties. So when we convert the dictionary to a list for the first item, we will find the attribute of the properties and store them in the AttributeDictionaryList. For the next models, we will get their attributes, from this list. So we will improve the performance.

3-) We will change “Attribute.IsDefined()” with the custom “CheckAttribute()” method and after the first one, we can get attributes of property from the Dictionary.

This is the performance test between using Reflection(Attribute.IsDefined()) for all items and using only one item(CheckAttribute()).

“That’s been one of my mantras — focus and simplicity. Simple can be harder than complex…”

— Steve Jobs

DictionaryToList<T> Extension (FINAL Version):

Program.cs(Final): UsingDictionaryToList()” extension.

1-) “dictList” is our test dictionary list. We will convert it to a list. List<Email> is our complex Recipient’s property test value.

2-) We will add 10000 rows to the dictionary lists. “uniqueKey” is our ignored key. It is a unique string name for every dictionary. There is no mapped property on DB for this key. We will use it for keeping singularity in the dictionary. If we find any record with the same key, we will remove and update it with the latest dictionary.

3-) “columnMatchTable” is our matching config list, like AutoMapper. We will run our DictionaryToList() extension 5 times for 5 * 10000 = 50000 records. And monitoring the result.

“Nature is pleased with simplicity.”

— Isaac Newton.

Test Dictionary to List Performance

Conclusion:

In this article, we tried to convert a dictionary to a list without matching the columns one by one. While doing this we used generic and reflection class. I know reflection is a performance killer but if you have 100 column tables and readability is so important for you, you can use this extension without any hesitate. I tried to boost codes with storing attributes in a scoped dictionary. But if it is not enough for you, you can keep all “class.table.column.attributes” in a global static dictionary list on startup. And maybe you can overload “dictList.DictionaryToList(ColumnMatchTable, bool hasAttribute=true)”. If your class’s properties have no attributes, you can set the “hasAttribute” field to false and not make any check for “ToJson()” or any attribute operations.

See you until the next article.

“If you have read so far, first of all, thank you for your patience and support. I welcome all of you to my blog for more!”

Github: https://github.com/borakasmer/DictionaryToList

--

--

A new tech publication by Start it up (https://medium.com/swlh).

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Bora Kaşmer

I have been coding since 1993. I am computer and civil engineer. Microsoft MVP. Senior Software Architect. Ride motorcycle. Gamer. Have two daughters.