How to map dictionary with values containg tuples to class instance - c#

I have a dictionary of type Dictionary<string, (int Id, string Code, string Name)>:
var dict = new Dictionary<string, (int Id, string Code, string Name)>
{
["subjectType"] = (1, "1Code", "1Name"),
["residentType"] = (2, "2Code", "2Name"),
["businessType"] = (3, "3Code", "3Name"),
// and so on...
};
I use tuple (int Id, string Code, string Name) here but I can replace it with a class. So, it doesn't matter tuple or class, I just need to have three properties (Id, Code, Name) for each dictionary item.
I need to project this dictionary into a class, so I map each property of output model separately like this:
public static OutputModel Map(
Dictionary<string, (int Id, string Code, string Name)> dictionary) =>
new OutputModel
{
SubjectTypeId = dictionary["subjectType"].Id,
SubjectTypeCode = dictionary["subjectType"].Code,
SubjectTypeName = dictionary["subjectType"].Name,
ResidentTypeId = dictionary["residentType"].Id,
ResidentTypeCode = dictionary["residentType"].Code,
ResidentTypeName = dictionary["residentType"].Name,
BusinessTypeId = dictionary["businessType"].Id,
BusinessTypeCode = dictionary["businessType"].Code,
BusinessTypeName = dictionary["businessType"].Name,
// and so on...
};
I wonder is there any other (more fancy) way to do the same mapping?

You could do the following.
var outPutModel = new OutputModel();
foreach (var keyValuePair in dictionary)
outPutModel.Write(keyValuePair);
public class OutputModel
{
public void Write(KeyValuePair<string, (int Id, string Code, string Name)> keyValuePair)
{
var type = typeof(OutputModel);
type.GetProperty(keyValuePair.Key + "Id", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public).SetValue(this, keyValuePair.Value.Id);
type.GetProperty(keyValuePair.Key + "Code", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public).SetValue(this, keyValuePair.Value.Code);
type.GetProperty(keyValuePair.Key + "Name", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public).SetValue(this, keyValuePair.Value.Name);
}
}
See it in action:
https://dotnetfiddle.net/jfKYsG

Related

creating IList<T> values at runtime from variables

Im getting data from a solaceconnection which returns data as so {Account:"023": hasAccount:true} and I need to break it up and put it into two list (IList names and IList values). Names will be "Account" and "hasAccount" which I am able to do. But, Im having a problem with values. I am trying to get the type of the values ("023" and true in this example) and creating IList of type string" for "023" and IList of type bool for true. I have been trying the below but
Cache.ToList().ForEach(row => {
List<string> _namesList = new List<string>();
List<object> _valuesList = new List<object>();
FieldInfo[] fields = row.GetType().GetFields(BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance);
fields.ToList().ForEach(field => {
var fieldName = field.Name;
var fieldValue = field.GetValue(row);
_namesList.Add(fieldName);
var m_oEnum = Activator.CreateInstance(fieldValue.GetType(), new object[] { 1 }); // Length 1
//var m_oEnum = new propertyType[] { fieldValue };
_valuesList.Add(m_oEnum);
});
});
My intentions with var m_oEnum is to create a IList or array of type stirng or bool and set the fieldvalue in it. But Im not able to do it since i get the exception thrown "Constructor on type 'System.Boolean' not found." for line
var m_oEnum = Activator.CreateInstance(objectType, new object[] { 1 }); // Length 1
is it possible to create an array on the fly with a datatype and place the value in it? Thanks
Value types should be handled differently.
Cache.ToList().ForEach(row => {
List<string> _namesList = new List<string>();
List<object> _valuesList = new List<object>();
FieldInfo[] fields = row.GetType().GetFields(BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance);
fields.ToList().ForEach(field => {
var fieldName = field.Name;
var fieldValue = field.GetValue(row);
_namesList.Add(fieldName);
var objectType = fieldValue.GetType();
if (objectType.IsValueType)
{
_valuesList.Add(fieldValue);
}
else
{ // What about types without a parameterless constructor?
var m_oEnum = Activator.CreateInstance(objectType, new object[] { 1 }); // Length 1
_valuesList.Add(m_oEnum);
}
});
});

How to set class fields using keys?

I wrote a generic method which should let us send type, an array which includes field names and an array which includes field values. I need to get class field by key from a dictionary and set value from dictionary to these fields and create new instance of this object
private static T test<T>(T obj, string[] fieldArr, string[] valueArr)
{
Type type = obj.GetType();
List<string> data = new List<string>();
var bindingFlags = BindingFlags.Instance |
BindingFlags.NonPublic |
BindingFlags.Public;
List<PropertyInfo> props = type.GetProperties(bindingFlags).ToList();
Dictionary<string, string> dict = new Dictionary<string, string>();
FieldInfo[] fieldInfos = type.GetFields();
for (int i = 0; i < fieldArr.Length; i++)
{
dict.Add(fieldArr[i], valueArr[i]);
}
var de = new List<PropertyInfo>();
foreach (var item in dict)
{
var fi = type.GetProperty(item.Key);
object obji = null;
fi.SetValue(obji, item.Value);
de.Add(fi);
}
return T;
}
Any suggestions?

Multiple lines and columns in Specflow

I have a Specflow table that looks like this.
When I Perform POST Operation for "/example/" with body
| answerValue1 | answerValue2 | countryCode | Cash |
| Yes | Yes | AD | 76-100% |
| | | AF | |
The column CountryCode is the only one that can be multiple choices.
What I tried to do was to add the columns to dictionary with a simple tableExtenstions
public class TableExtensions
{
public static Dictionary<string, string> ToDictionary(Table table)
{
var dictionary = new Dictionary<string, string>();
foreach (var row in table.Rows)
{
dictionary.Add(row[0], row[1]);
}
return dictionary;
}
}
and call it from the method.
var dictionary = TableExtensions.ToDictionary(table);
var countryCode = dictionary["countryCode"];
Unfortnally I get error The given key was not present in the dictionary,
since the dictionary only returns two values from the first and the second Key
Ofcourse if I change the keys to row[2], row[3] it gets the right columns.
But I would like to reuse the Table Extension.
Also i tried to increment them, but it only took the first to columns
var i = 0;
foreach (var row in table.Rows)
{
dictionary.Add(row[i], row[i]);
i++;
}
Does anyone has a better solution?
I'm not entirely sure what you want the dictionary to ultimately contain, but as you mention that manually changing the rows it looks for to:
row[2], row[3]
gives the data you want, perhaps this would give you the reusability you're looking for:
public class TableExtensions
{
public static Dictionary<string, string> ToDictionary(Table table, int columnOne, int columnTwo)
{
int i = 0;
var dictionary = new Dictionary<string, string>();
foreach (var row in table.Rows)
{
dictionary.Add(row[columnOne], row[columnTwo]);
}
return dictionary;
}
}
Usage:
var dictionary = TableExtensions.ToDictionary(table, 2, 3);
This produces a dictionary with the following contents:
You could get the country code like this:
foreach (var row in dictionary)
{
var countryCode = row.Key;
var score = row.Value ?? string.empty;
}
Given the simplicity of the country codes I would make them a comma separated list and use a vertical table instead:
When I Perform POST Operation for "/example/"
| Field | Value |
| answerValue1 | ... |
| answerValue2 | ... |
| countryCodes | AD, AF |
| cash | ... |
In your step definition:
var example = table.CreateInstance<ExampleRow>();
// use example.GetCountryCodes();
And the ExampleRow class to parse the table into an object:
public class ExampleRow
{
public string AnswerValue1 { get; set; }
public string AnswerValue2 { get; set; }
private string[] countryCodes;
public string CountryCodes
{
get => string.Join(", ", countryCodes);
set => countryCodes = value.Split(", ");
}
public string[] GetCountryCodes()
{
return countryCodes;
}
}

GetValue reflection on iterating through collections and get item.ToString()

Inside Class TestClass:
public HashSet<string> Test = new HashSet<string>();
public List<string> Test2 = new List<string>() {"item1"};
public String Test3 = "lol";
Getting all properties with reflection:
TestClass c = new TestClass();
var properties = c.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
Now I want to iterate through the collection properties only:
var value = property.GetValue(c);
if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType) && property.PropertyType != typeof(string))
{
var valueString = string.Empty;
foreach (var item in (IEnumerable)value)
{
valueString += item.ToString() + " | ";
}
}
Works fine. Except when the collection is empty I get the collection fullname on item.ToString() instead of nothing / string.empty:
Output:
for the list I get a valueString with "item1" but for the HashSet I get a valueString of "TestClass.HashSet"
Any way to fix that?

List all SystemColors

In Windows.Forms, I need to create a program which accepts any color and tries to find the corresponding system colors to it.
I was not able to figure out how to loop through all Colors of the System.Drawing.SystemColors class - it's a class, not an enum or a List.
How can I do this (some kind of reflection?)?
How about
public static Dictionary<string,object> GetStaticPropertyBag(Type t)
{
const BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
var map = new Dictionary<string, object>();
foreach (var prop in t.GetProperties(flags))
{
map[prop.Name] = prop.GetValue(null, null);
}
return map;
}
or
foreach (System.Reflection.PropertyInfo prop in typeof(SystemColors).GetProperties())
{
if (prop.PropertyType.FullName == "System.Drawing.Color")
ColorComboBox.Items.Add(prop.Name);
}
And I cooked something up.
var typeToCheckTo = typeof(System.Drawing.Color);
var type = typeof(System.Drawing.SystemColors);
var fields = type.GetProperties(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public).Where(p => p.PropertyType.Equals(typeToCheckTo));
foreach (var field in fields)
{
Console.WriteLine(field.Name + field.GetValue(null, null));
}

Categories