I working on a string tokenizer function.
This is the sample object
var obj= new
{
Order= new
{
CustomerName = "John",
OrderTotal= "10.50",
Qty =2,
Address= new
{
Street= "Park Road",
Country= "UAS"
}
}
};
I need to get property vs values onto Dictionary<string, string>
expecting result :
<Order.CustomerName,"John">
<Order.OrderTotal,"10.50">
<Order.Qty ,"2">
<Order.CustomerName.Address.Street,"Park Road">
<Order.CustomerName.Address.Country,"USA">
This is how I tried
private Dictionary<string, string> GetValueByPropertyToken(object obj)
{
var result = new Dictionary<string, string>();
// get the type:
var objType = obj.GetType();
// iterate the properties
var prop = (from property in objType.GetProperties() select property).ToList();
foreach (var item in prop)
{
var name = item.Name;
var nextProperty = item?.GetValue(obj);
}
return result;
}
CodePudding user response:
You can achieve this via recursion and reflection:
Extension.cs class:
public static class Extensions
{
/// <summary>
/// Extension method for object to explode to dictionary.
/// </summary>
/// <param name="values"></param>
/// <returns>Dictionary with key-value pairs for prefix and primite values</returns>
public static IDictionary<string, object> ToDictionary(this object values)
{
var dict = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
GetValues("", values, dict);
return dict;
}
/// <summary>
/// Recursively go through obj and explode into key-value pairs for prefix value
/// </summary>
/// <param name="prefix">Prefix for key</param>
/// <param name="obj">The object to explode</param>
/// <param name="dict">The resulting dictionary</param>
private static void GetValues(string prefix, object obj, Dictionary<string, object> dict)
{
var properties = TypeDescriptor.GetProperties(obj);
// Base case
if (properties.Count == 0) return;
// Go through all children objects
foreach (PropertyDescriptor property in properties)
{
// Get next object and prefix
var nextObject = property.GetValue(obj);
string nextPrefix = (String.IsNullOrEmpty(prefix) ? property.Name : $"{prefix}.{property.Name}");
// If it´s generic we continue down the object
// If it´s primitive we add it to the dictionary
if (nextObject.GetType().IsGenericType)
GetValues(nextPrefix, nextObject, dict);
else
dict.Add(nextPrefix, nextObject);
}
}
}
Program.cs class:
private static void Main(string[] args)
{
var obj = new
{
Order = new
{
CustomerName = "John",
OrderTotal = "10.50",
Qty = 2,
Address = new
{
Street = "Park Road",
Country = "UAS"
}
}
};
var dict = obj.ToDictionary();
foreach(string key in dict.Keys)
{
Console.WriteLine($"{key}: {dict[key]}");
}
}
The output:
Order.CustomerName: John Order.OrderTotal: 10.50 Order.Qty: 2 Order.Address.Street: Park Road Order.Address.Country: UAS
Be careful that this code probably won´t handle more complicated scenarios involving arrays and other complicated data structures. You will have to expand on this code to fulfill your needs.
CodePudding user response:
firslty, you did not add dictionary object (result
), secondly for sub element you have to call it again.
public Dictionary<string,string> GetDictionaryByObject(object obj)
{
{
var dict = new Dictionary<string, string>();
foreach (var prop in obj.GetType().GetProperties())
{
if (prop.PropertyType.IsPrimitive || prop.PropertyType == typeof(string))
{
dict.Add(prop.Name, prop.GetValue(obj).ToString());
}
else
{
var subDict = GetDictionaryByObject(prop.GetValue(obj));
foreach (var subProp in subDict)
{
dict.Add($"{prop.Name}.{subProp.Key}", subProp.Value);
}
}
}
return dict;
}
}
Result: