C# - Object List to Dictionary - c#

Is there a way to assign the key values of each object in a List to a Dictionary? I want to access that dictionary later to assign the values to properties of a class.
I fetch some values from a BD with inner joins, then I store the values in a list of objects:
IEnumerable<object> units = _unitDetailsQuery.Execute<object>(out totalRecords);
Each object has these properties:
Brand (string)
Model (string)
Code (string)
BranchId (int)
Then I create a Dictionary
IDictionary<string, object> props = new Dictionary<string, object>();
I've seen in another question something like this (i've adapted the snippet to my code):
BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance;
foreach (object unit in units)
{
props = unit.GetType().GetProperties(bindingAttr).ToDictionary
(
propInfo => propInfo.Name,
propInfo => propInfo.GetValue(unit, null)
);
}
But props gets no value after the assignment.
Internally the object is something like this:
So how do I get those values? Thanks in advance.

You can use this extension method, which will reflect over the object's public properties and put them into a dictionary.
public static class ObjectExtensionMethods
{
static public Dictionary<string, object> ToPropertyDictionary(this object o)
{
var d = new Dictionary<string, object>();
foreach (var p in o.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
d.Add(p.Name, p.GetValue(o));
}
return d;
}
}
You could use this on a list of objects like so:
var listOfDictionaries = listOfObjects.Select( o => o.ToPropertyDictionary() );

Giving credit to #John Wu, but since you said you wanted information to be editable, I think the extension method instead has to return string, System.Reflection.PropertyInfo instead. That way, properties can be updated and selected.
public static Dictionary<string, System.Reflection.PropertyInfo> ToPropertyDictionary(object o)
{
var d = new Dictionary<string, System.Reflection.PropertyInfo>();
foreach (var p in o.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
d.Add(p.Name, p);
}
return d;
}
This way, you can get/set the original object's properties. It could no longer be an extension method.
This way, you can edit the object like so. Let's say I have a random object named o with a variable named X that's an integer.
Then, I can get the dictionary.
var dict = ToPropertyDictionary(o);
Setting X with a value of 2 can be done with:
dict("X").SetValue(o, 2);
Getting X then would be done with:
dict("X").GetValue(o)

Related

How do I use MemoryCache to speedup translation of various objects into strings?

I have a large dataset (IEnumerable of [Table]-attributed class objects) from a Linq-To-Sql query and I need to produce a CSV file from it. I loop over the dataset and for each item I convert the value of each property of the item into a string using various formatting options.
Type t = typeof(T);
var properties = t.GetProperties();
foreach (var item in list)
{
foreach (var property in properties)
{
// This is made using delegates, but whatever
object value = property.GetValue(item, null);
// convert to string and feed to StringBuilder
}
}
The problem is that conversion takes even longer that running the query. The dataset contains heavily denormalized data - numerous items have the same properties having the same values and only some properties having different values. Each property value is translated separately for each item in the dataset. So my code converts the same data into the same strings - over and over. And I'd like to somehow speed this up, preferable without changing the SQL query.
Looks like MemoryCache class could work, but I need to craft unique keys for each object. I can't figure out how I could craft such keys reliably and efficiently enough.
How do I make use of MemoryCache so that I can cache translation results for objects of different types?
If you just want to speed it up I would suggest ExpressionTrees more than MemoryCache. This assumes you don't have nested objects to want to read and I can use reflection on the first item and it will be the same for each item in the IEnumerable - which from your example code in the question seems correct.
Also if it's big and you are going to just write it out to a file I would suggest going straight to a FileStream instead of a StringBuilder.
public class CSV
{
public static StringBuilder ToCSV(IEnumerable list)
{
Func<object, object[]> toArray = null;
var sb = new StringBuilder();
// Need to initialize the loop and on the first one grab the properties to setup the columns
foreach (var item in list)
{
if (toArray == null)
{
toArray = ItemToArray(item.GetType());
}
sb.AppendLine(String.Join(",", toArray(item)));
}
return sb;
}
private static Func<object, object[]> ItemToArray(Type type)
{
var props = type.GetProperties().Where(p => p.CanRead);
var arrayBody = new List<Expression>();
// Create a parameter to take the item enumeration
var sourceObject = Expression.Parameter(typeof (object), "source");
// Convert it to the type that is passed in
var sourceParam = Expression.Convert(sourceObject, type);
foreach (var prop in props)
{
var propType = prop.PropertyType;
if (IsValueProperty(propType))
{
// get the value of the property
Expression currentProp = Expression.Property(sourceParam, prop);
// Need to box to an object if value type
if (propType.IsValueType)
{
currentProp = Expression.TypeAs(currentProp, typeof (object));
}
// Add to the collection of expressions so we can build the array off of this collection
arrayBody.Add(currentProp);
}
}
// Create an array based on the properties
var arrayExp = Expression.NewArrayInit(typeof (object), arrayBody);
// set a default return value of null if couldn't match
var defaultValue = Expression.NewArrayInit(typeof (object), Expression.Constant(null));
//Set up so the lambda can have a return value
var returnTarget = Expression.Label(typeof (object[]));
var returnExpress = Expression.Return(returnTarget, arrayExp, typeof (object[]));
var returnLabel = Expression.Label(returnTarget, defaultValue);
//Create the method
var code = Expression.Block(arrayExp, returnExpress, returnLabel);
return Expression.Lambda<Func<object, object[]>>(code, sourceObject).Compile();
}
private static bool IsValueProperty(Type propertyType)
{
var propType = propertyType;
if (propType.IsGenericType && propType.GetGenericTypeDefinition() == typeof (Nullable<>))
{
propType = new NullableConverter(propType).UnderlyingType;
}
return propType.IsValueType || propType == typeof (string);
}
}

pass class type as parameter c# and used with dictionary

I am create a function to return a dictionary and I want to pass class name through as a parameter. But its gives an error. Code i have written is given below
public Dictionary<object, object> GetDetails(Type Classname)
{
MvcDemoDBEntities db = new MvcDemoDBEntities();
Dictionary<Classname, object> dict = new Dictionary<Classname, object>();
var data = (from h in db.People
select h).ToList();
foreach (var item in data)
{
dict.Add(data, true);
}
return dict;
}
what am i doing wrong
and i would like to call this function with a class name dynamically, like this :
List<people> list = GetDetails(people).Keys.ToList();
people its my class name.
Using Generics
Your current approach will give you much trouble. As you are going to pass a Type object for your class, you will need reflection to be able to create the Dictionary.
As an alternative, I propose to you to create a generic method:
public Dictionary<object, object> GetDetails<TClass>()
{
MvcDemoDBEntities db = new MvcDemoDBEntities();
Dictionary<TClass, object> dict = new Dictionary<TClass, object>();
var data = (from h in db.People
select h).ToList();
foreach (var item in data)
{
dict.Add(data, true);
}
return dict;
}
Use it like this:
List<people> list = GetDetails<people>().Keys.ToList();
Using Type
Of course, this can be done using a Type object, this requiers the use of reflection to be able to create an object of which type we don't know (that object is the dictionary). This is done as follows:
public Dictionary<object, object> GetDetails(Type Class)
{
//Null check
if (null == Class)
{
throw new ArgumentNullException("Class");
}
MvcDemoDBEntities db = new MvcDemoDBEntities();
//Get the generic dictionary type:
Type DictType = typeof(Dictionary<,>).MakeGenericType(Class, typeof(object));
//Create the dictionary object:
object dict = Activator.CreateInstance(typeof(DictType));
//Get the Add method:
var add = DictType.GetMethod("Add", new Type[]{Class, typeof(object)});
var data = (from h in db.People
select h).ToList();
foreach (var item in data)
{
//add to the dictionary:
add.Invoke(dict, new object[]{item, true});
}
return dict;
}
Use like this:
List<people> list = GetDetails(typeof(people)).Keys.ToList();
Digging deeper
I notice you have this line:
var data = (from h in db.People select h).ToList();
You may be interested in changing People to a property matching the name of the class you pass in. This can only be archived via reflection. In a similar way as how we got the Add method of the dictionary, we can get a property from the object db which name is given by the argument type.
I'll present this as a second method to be called by the first.
Using Generics
public IEnumerable<TClass> GetCollection<TClass>(MvcDemoDBEntities db)
{
//get the type of db
var dbType = db.GetType();
//get the name of the type TClass
var name = typeof(TClass).Name;
//get the property
var prop = dbType.GetProperty(name);
//read the property and return
return prop.GetValue(db);
}
To use, replace this:
var data = (from h in db.People select h).ToList();
With this:
var data = (from h in GetCollection<TClass>(db) select h).ToList();
Using Type
Here the struggle is that we don't know the item type... so I'll use IEnumerable.
public IEnumerable GetCollection(MvcDemoDBEntities db, Type Class)
{
//get the type of db
var dbType = db.GetType();
//get the name of the type Class
var name = Class.Name;
//get the property
var prop = dbType.GetProperty(name);
//read the property and return
return prop.GetValue(db);
}
To use, replace this:
var data = (from h in db.People select h).ToList();
With this:
var data = (from h in GetCollection(db, Class).Cast<object>() select h).ToList();
You need to use typeof to pass the type of your class
List<people> list = GetDetails(typeof(people)).Keys.ToList();

Project dynamic Dapper results excluding some properties

Given a dynamic Dapper query such as:
var results = connection.Query<dynamic>("SELECT ....");
I want to remove a couple of the returned columns/properties from the results. The trick is I want to do this without knowing/caring the names of the properties I want to keep, otherwise I would simply project the results into a new anonymous type.
I attempted to loop through the results and cast each to an IDictionary<string, object> so that I could simply remove the key/value pair holding the data. Unfortunately, for whatever reason, the underlying internal FastExpando object doesn't implement the Remove method. The source code for FastExpando shows:
bool IDictionary<string, object>.Remove(string key)
{
throw new NotImplementedException();
}
How can I implement this? To be clear I basically want:
var filteredResults = from r in results
select new { // All properties except a couple of well-known ones }
There was no reason that FastExpandoObject didn't implement those methods, other than: it hadn't needed to. I have now filled in all the missing / NotImplementedException methods. I haven't yet deployed to NuGet, but the code on github/google-code has been updated.
What if you iterate the FastExpandoObject and return a filtered ExpandoObject?
var filteredResults = dynamicResult.Select<dynamic, dynamic>(x =>
{
var filteredRow = new ExpandoObject() as IDictionary<string, Object>;
var props = x as IDictionary<string, object>;
foreach (var prop in props)
{
if (!filter.Contains(prop.Key))
filteredRow.Add(prop);
}
return filteredRow;
});

How to add a value to a dictionary using reflection in c#?

I have the following Dictionary:
private Dictionary<string, double> averages = new Dictionary<string, double>();
Now I want to use reflection to add two additional values. I can retrieve the field info, but what else do I have to do?
FieldInfo field = ProjectInformation.SourceManager.GetType().GetField("averages");
if (field != null)
{
//what should be here?
}
MethodInfo mi = field.FieldType.GetMethodInfo("set_Item");
Object dict = field.GetValue(ProjectInformation.SourceManager);
mi.Invoke(dict, new object[] {"key", 0.0} );
If you need to get the field and values just for Unit Testing consider using Microsoft's PrivateObject
Its there so you can check the internal state of data members during unit testing if you need to, which appears to be what you are trying to do.
In your unit tests you can do the following:
MyObject obj = new MyObject();
PrivateObject privateAccessor = new PrivateObject(obj);
Dictionary<string, double> dict = privateAccessor.GetFieldOrProperty("averages") as Dictionary<string, double>;
Then you are free to get and set any values you need to from the Dictionary.
if(field != null)
{
field.GetValue(instance);
}

C# properties as array notation

Using JavaScript it's possible to access an object using the dot notation or array notation.
var myArray = {e1:"elem1",e2:"elem2",e3:"elem3",e4:"elem4"};
var val1 = myArray["e1"];
var val2 = myArray.e1;
Is it possible to accomplish this using C#?
This is what I have attempted:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection frmVals)
{
string value;
Owner owner = new Owner();
foreach (var key in frmVals.AllKeys)
{
value = frmVals[key];
owner[key] = value;
}
}
While there is no way to do this exactly with C#. You could change your code in several ways that may accomplish your goal. First, you could use a Dictionary like this:
var something = new Dictionary<string, object>() {
{ "property", "value"},
{ "property1", 1}
};
foreach (var keyVal in something) {
var property = keyVal.Key;
var propertyValue = keyVal.Value;
}
Another option would be to do it dynamically:
dynamic somethingDyn = new System.Dynamic.ExpandoObject();
somethingDyn.property = "value";
somethingDyn.property1 = 1;
var somethingDynDict = (IDictionary<string, object>)somethingDyn;
var propValue = somethingDyn["property"];
foreach (var keyVal in somethingDynDict) {
var property = keyVal.Key;
var propertyValue = keyVal.Value;
}
If you need to iterate through properties on a strongly typed object you could use reflection:
var owner = new Metis.Domain.User();
var properties = owner.GetType().GetProperties();
foreach (var prop in properties) {
object value = prop.GetValue(owner, null);
}
I wouldn't recommend this, but you could put an indexer in your class, accepting a string, then use reflection to read that property. Something like:
public object this[string key]
{
get
{
var prop = typeof(ThisClassName).GetProperty(key);
if (prop != null)
{
return prop.GetValue(this, null);
}
return null;
}
set
{
var prop = typeof(ThisClassName).GetProperty(key);
if (prop != null)
{
prop.SetValue(this, value, null);
}
}
}
Javascript array notation is not something you can use in C#.
You need to use dot notation to access members of an object.
You will need to access each value directly and assign it:
owner.key = frmVals[key];
owner.key2 = frmVals[key2];
There are workarounds - using dictionaries, dynamic objects or even reflection, but the scenario is not a directly supported by C#.
There is no syntactic equivalent possible in C# but there are some ways to approximate the same feature.
You could mimic the indexer type access using a Dictionary but then you'd lose the property-style access. For property-style access, you could do something similar in C# by using an anonymous type, as in:
var myType = new { e1="elem1",e2="elem2",e3="elem3",e4="elem4"};
var val1 = myType.e1;
However, that doesn't create an array or allow array type access and it doesn't allow for modifications to the type after creation.
To get a closer approximation to the JavaScript feature, you may be able to use ExpandoObject to mimic this a little more closely, or you could implement something yourself.
For that, you'd need a class that has a constructor to auto-generate properties from the passed in array and exposes an indexer, which in turn uses reflection to find the named property.
Initialization of this type would be something like:
var myType = new MyType(new[]{
{"e1", "elem1"},
{"e2", "elem2"},
{"e3", "elem3"},
{"e4", "elem4"}});
This assumes there is a sub-type for each element definition (possibly using Tuple or KeyValuePair. The constructor would then be taking an IEnumerable<T> of that type.
Yes, it's possible.
There are two possibilities:
1) The list of keys and values is dynamic.
The array notation is provided by e.g. System.Collections.Generic.Dictionary<string, blah>
The member access notation can be provided through DLR magic and the dynamic keyword.
2) The list of keys and values is static.
Member access notation is already provided by the C# compiler.
Array notation can be had using Reflection (hopefully with a cache to improve performance).
In the static case, member access notation is MUCH faster. In the dynamic case, array notation will be a little faster.

Categories

Resources