automapper map dynamic object - c#

I am working with Automapper and need to achieve the following mapping but not sure how it can be done.
I want to map a Dictionary object to a dynamic object, so that the key is the property on the object and the value of the dictionary is the value of property in dynamic object.
Can this be achieve with automapper and if so, how?

You can simply get Dictionary from ExpandoObject and fill it with original dictionary values
void Main()
{
AutoMapper.Mapper.CreateMap<Dictionary<string, object>, dynamic>()
.ConstructUsing(CreateDynamicFromDictionary);
var dictionary = new Dictionary<string, object>();
dictionary.Add("Name", "Ilya");
dynamic dyn = Mapper.Map<dynamic>(dictionary);
Console.WriteLine (dyn.Name);//prints Ilya
}
public dynamic CreateDynamicFromDictionary(IDictionary<string, object> dictionary)
{
dynamic dyn = new ExpandoObject();
var expandoDic = (IDictionary<string, object>)dyn;
dictionary.ToList()
.ForEach(keyValue => expandoDic.Add(keyValue.Key, keyValue.Value));
return dyn;
}

Here's en example, but if you drop a comment or elaborate your post it could be more descriptive. Given this class:
class Foo
{
public Foo(int bar, string baz)
{
Bar = bar;
Baz = baz;
}
public int Bar { get; set; }
public string Baz { get; set; }
}
You can create a dictionary of its public instance properties and values this way:
var valuesByProperty = foo.GetType().
GetProperties(BindingFlags.Public | BindingFlags.Instance).
ToDictionary(p => p, p => p.GetValue(foo));
If you want to include more or different results, specify different BindingFlags in the GetProperties method. If this doesn't answer your question, please leave a comment.
Alternatively, assuming you're working with a dynamic object and anonymous types, the approach is similar. The following example, clearly, doesn't require the class Foo.
dynamic foo = new {Bar = 42, Baz = "baz"};
Type fooType = foo.GetType();
var valuesByProperty = fooType.
GetProperties(BindingFlags.Public | BindingFlags.Instance).
ToDictionary(p => p, p => p.GetValue(foo));

Related

Changing object property while storing it in list

lets say i have class with a lot of redundant properties and i want to store them in list, dictionary or whatever
public class Foo
{
public Bar Bar1 {get;set;}
public Bar Bar2 {get;set;}
public Bar Bar3 {get;set;}
public Buzz Buzz1 {get;set;}
public Buzz Buzz2 {get;set;}
public Buzz Buzz3 {get;set;}
public void UpdateObject(Buzz newValue)
{
var dict = new List<KeyValuePair<Bar, Func<Buzz >>>()
{
new KeyValuePair<Bar, Func<Buzz>>(this.Bar1 ,()=>this.Buzz1),
new KeyValuePair<Bar, Func<Buzz>>(this.Bar2 ,() => this.Buzz2 ),
new KeyValuePair<Bar, Func<Buzz>>(this.Bar3 ,() => this.Buzz3 )
};
foreach (var item in dict)
{
if (true)
{
var value = item.Value.Invoke();
value = newValue;
}
}
}
}
of course value is changed but Foo's Buzz1/2/3 property is not. How can i store some kind of reference to object's property in list, get this item and change object's value?
Instead of the key value pairs with a key and a setter, store a key, a getter, and a setter:
List<Tuple<Bar, Func<Buzz>, Action<Buzz>>
Action<Buzz> is a lambda that takes a new value for that Buzz as a parameter.
var dict = new List<Tuple<Bar, Func<Buzz>, Action<Buzz>>
{
new Tuple<Bar, Func<Buzz>, Action<Buzz>(this.Bar1 ,()=>this.Buzz1, x => this.Buzz1 = x),
// ...etc...
};
Not sure why you're doing this, but that'll work.
If it were me, instead of a Tuple or KeyValuePair, I'd write a ThingReference<T> class that takes the two lambdas, and store those in a Dictionary<Bar, ThingReference<Buzz>>.

Convert Dictionary<string, object> to a collection of objects with key

Is there a way to convert Dictionary<string, obj> to collection of objects such that each single object in the collection includes the key as another property
Here is the class def for obj
class someclass
{
string property1;
string property2;
}
After conversion, I am expecting each object in the collection to be like
obj.property1
obj.property2
obj.Key
I have been struggling with this since along time and I seek some help. any ideas?
thanks in advance.
Something like
var myCollection = from de in myDictionary
select new
{
de.Value.property1,
de.Value.property2,
de.Key
}.ToList(); // or .ToArray()
should do the trick.
That will return a List of a new anonymous type with the properties you requested.
You could also(in addition to the anonymous type apporach) use a List<Tuple<string, string, string>>:
var list= dictionary
.Select(kv => Tuple.Create(kv.Value.property1, kv.Value.property2, kv.Key))
.ToList();
foreach(var item in list)
{
Console.WriteLine("property1:{0 property2:{1} key:{2}"
, item.Item1
, item.Item2
, item.Item3);
}
The advantage over an anonymous type is that you can return the Tuple easily from a method.
Edit: A third option(my favorite) is simply to create instances of a class that you've declared somewhere. That's the ideal way. I don't know why i thought that you want a class "on the fly".
class someOtherClass
{
public string property1{ get; set; };
public string property2{ get; set; };
public string Key{ get; set; };
}
List<someOtherClass> objects = dictionary
.Select(kv => new someOtherClass(){
property1 = kv.Value.property1,
property2 = kv.Value.property2,
Key = kv.Key
})
.ToList();
You may use anonymous type if you don't want to store the result like this:
In case you just wana use it as datasource for example.
var res = myDictionary.Select(pair => new { pair.Key, pair.Value.Property1, pair.Value.Property2 });
The other answers are good, so this is just a supplement.
You could use arrays of Length three:
var arrays = myDictionary
.Select(kv => new[] { kv.Value.property1, kv.Value.property2, kv.Key, });
Or you could write a new class
class SomeclassAndKey
{
public string property1;
public string property1;
public string Key;
}
and then say
var someclassAndKeys = myDictionary
.Select(kv => new SomeclassAndKey { property1 = kv.Value.property1, property2 = kv.Value.property2, Key = kv.Key, });
In each case you could append .ToList() if you wanted not to defer enumeration and get a full List<> out.

Serializing ExpandoObject with ServiceStack.Text

I am trying to serialize objects with the library ServiceStack.Text . This works
using System.Dynamic;
using ServiceStack.Text;
var x = new {Value= 10, Product = "Apples"};
Console.WriteLine(JsonSerializer.SerializeToString(x));
I get, as I expect
{"Value":10,"Product":"Apples"}
However
dynamic x = new ExpandoObject();
x.Value = 100;
x.Product = "Apples";
Console.WriteLine(JsonSerializer.SerializeToString(x));
I get to my surprise
[{"Key":"Value","Value":100},{"Key":"Product","Value":"Apples"}]
Why! What's going on?
Secondly, how can I get what I want?
ExpandoObject implements IConnection<KeyValuePair> and IEnumerable<KeyValuePair>:
public sealed class ExpandoObject :
IDynamicMetaObjectProvider,
IDictionary<string, object>,
ICollection<KeyValuePair<string, object>>,
IEnumerable<KeyValuePair<string, object>>,
IEnumerable, INotifyPropertyChanged
My guess is that internally, the ServiceStack serializer is treating the ExpandoObject as an IEnumerable<KeyValuePair>, and so it serializes to a JSON array of key/value pairs.
This differs from your first (working) code snippet because .NET actually builds a real (anonymous) class for your data, basically it makes:
public class SomeNameTheCompilerMakesUp {
internal int Value { get; set; }
internal string Product { get; set; }
}
for you automatically, so when it is sent to the serializer, it is working with a real class with real properties, whereas the ExpandoObject is really backed by an object[] internally.
On a side-note, Microsoft's System.Web.Helpers.Json behaves the same way. This test passes:
[TestMethod]
public void ExpandoObjectSerializesToJsonArray()
{
dynamic anonType = new { Value = 10, Product = "Apples" };
dynamic expando = new ExpandoObject();
expando.Value = 10;
expando.Product = "Apples";
var anonResult = System.Web.Helpers.Json.Encode(anonType);
var expandoResult = System.Web.Helpers.Json.Encode(expando);
Assert.AreEqual("{\"Value\":10,\"Product\":\"Apples\"}", anonResult);
Assert.AreEqual("[{\"Key\":\"Value\",\"Value\":10},{\"Key\":\"Product\",\"Value\":\"Apples\"}]", expandoResult);
}
One final edit:
You can make this work the way you want by turning your ExpandoObject into a Dictionary<string, object>. The caveat to this code is that it duplicates the data into a dictionary, so you have 2 copies in memory (or slightly less than, since technically the strings might be interned).
[TestMethod]
public void TestMethod1()
{
dynamic expando = new ExpandoObject();
expando.Value = 10;
expando.Product = "Apples";
// copy expando properties to dictionary
var dictionary = ((ExpandoObject)expando).ToDictionary(x => x.Key, x => x.Value);
var expandoResult = System.Web.Helpers.Json.Encode(expando);
var dictionaryResult = System.Web.Helpers.Json.Encode(dictionary);
Assert.AreEqual("[{\"Key\":\"Value\",\"Value\":10},{\"Key\":\"Product\",\"Value\":\"Apples\"}]", expandoResult);
Assert.AreEqual("{\"Value\":10,\"Product\":\"Apples\"}", dictionaryResult);
}
Although, for anyone that comes across this later, and is actually using System.Web.Helpers.Json, the better thing to do is just wrap your ExpandoObject in a DynamicJsonObject like this:
[TestMethod]
public void TestMethod1()
{
dynamic expando = new ExpandoObject();
expando.Value = 10;
expando.Product = "Apples";
var dictionaryResult = System.Web.Helpers.Json.Encode(new DynamicJsonObject(expando));
Assert.AreEqual("{\"Value\":10,\"Product\":\"Apples\"}", dictionaryResult);
}
Ans once I worked through that, I found a similar question here: How to flatten an ExpandoObject returned via JsonResult in asp.net mvc?

How do I project to a dictionary with a custom type using Linq to SQL?

I am attempting to use Linq to project each row from a DB query into a dictionary that has a custom type as its value. I am unsure of the LINQ syntax to do this?
This is my current attempt (which doesn't compile, but should demonstrate what I am trying to do). I am having trouble with the 'select new...' part.
public class MyClass
{
public Dictionary<int, CustomType> dict;
}
public class MyType{
string Name;
decimal Value;
}
var result = (from t in table
select new {
t.Id,
new MyType(t.Name,t.Value)
}).AsEnumerable().ToDictionary();
ANSWER:
Thanks Jason. I just used properties and automatic initialisers rather than a constructor. The working code resembles this (any improvements to this are welcome):
public class MyType {
public string Name {get;set;}
public decimal Value { get; set;}
}
Dictionary<int, CustomType> dict;
dict = (from t in table
select new {
id = av.Account.Id,
mt = new MyType { Name = t.Name, Value = t.Value }
}).ToDictionary(item => item.id, item => item.mt);
MyType doesn't have a constructor that takes two arguments.
Add the following to the definition of MyType:
public MyType(string name, decimal value) {
Name = name;
Value = value;
}
Further, you did not give the anonymous type member defined by
new MyType(t.Name, t.Value)
a name; try changing that line to:
MyType = new MyType(t.Name, t.Value)
The compiler will yell at you that it can not discern a name for this anonymous member.
Finally, there isn't an overload of ToDictionary that has no arguments. Assuming you named the above anonymous member to be MyType, change the call to ToDictionary to be
....ToDictionary(item => item.Id, item => item.MyType);

Using Reflection to set a Property with a type of List<CustomClass>

How can I use reflection to create a generic List with a custom class (List<CustomClass>)? I need to be able to add values and use
propertyInfo.SetValue(..., ..., ...) to store it. Would I be better off storing these List<>'s as some other data structure?
Edit:
I should have specified that the object is more like this, but Marc Gravell's answer works still.
class Foo
{
public List<string> Bar { get; set; }
}
class Foo
{
public string Bar { get; set; }
}
class Program
{
static void Main()
{
Type type = typeof(Foo); // possibly from a string
IList list = (IList) Activator.CreateInstance(
typeof(List<>).MakeGenericType(type));
object obj = Activator.CreateInstance(type);
type.GetProperty("Bar").SetValue(obj, "abc", null);
list.Add(obj);
}
}
Here's an example of taking the List<> type and turning it into List<string>.
var list = typeof(List<>).MakeGenericType(typeof(string));

Categories