Is it possible to use ExpandoObject to create run-time properties? - c#

Normally, we can create properties like this,
dynamic expando = new ExpandoObject();
expando.Price = 45k;
expando.Value = "Good";
In my case, I won't know the properties such as "Price" or "Value" until runtime. How, can I create such dynamic properties. Something like,
dynamic expando = new ExpandoObject();
expando[properties[0]] = 45k;
expando[properties[1]] = "Good";
expando[properties[2]] = "Red";
expando[properties[3]] = 8;
Anyway to achieve this kind of behavior.

Just use the fact that it implements IDictionary<string, Object>:
IDictionary<string, Object> expando = new ExpandoObject();
expando[properties[0]] = 45;
expando[properties[1]] = "Good";
expando[properties[2]] = "Red";
expando[properties[3]] = 8;
dynamic d = expando;
// Now use the properties as normal
On the other hand, if you don't know the properties until execution time, what's actually going to consume them? It may still make sense to use ExpandoObject - but equally it may make sense to use Dictionary<string, object> to start with.

Related

Serializing ExpandoObject with json.Net

I have the following code, where page.Fields is an ExpandoObject. I'm iterating through some user-defined properties and adding them to an Expando, cast to an IDictionary<string,string> to allow me to add new field name / values dynamically, but when I set the Fields property to the value of props, serializing afterwards only gives names with blank values of {}. Why?
page.Fields.Foo = "asdf";
var test = JsonConvert.SerializeObject(page); // shows Foo=asdf in the json
// attach all fields to the page object, casting to an IDictionary to be able to add var names
var props = new ExpandoObject() as IDictionary<string, Object>;
foreach (string key in Request.Form.Keys)
{
if (key.StartsWith("Fields."))
{
var fieldName = key.Substring(key.IndexOf(".") + 1);
props.Add(fieldName, Request.Form[key]);
}
}
var test2 = JsonConvert.SerializeObject(props); // blank values of {}
page.Fields = props as ExpandoObject;
// loses the values for the Fields property
test = JsonConvert.SerializeObject(page);
UPDATE the curse of Nancy strikes, the Request.Form values turned out to be dynamic, so I had to .ToString() it to make it fit into the expected IDictionary<string,string>
To correctly serialize the data you must declare the variable as dynamic, not as an ExpandoObject, JSON .net uses reflection to retrieve properties, if it's a dynamic it casts it as an ExpandoObject and uses the keys as property names, but if you pass the ExpandoObject directly it tries to retrieve the properties from the ExpandoObject type.
Just change
var props = new ExpandoObject() as IDictionary<string, Object>;
to
var props = new ExpandoObject();
var iProps = props as IDictionary<string, Object>;
Use iProps to add the data and pass props to the serialization.
EDIT:
You're storing the value in "Page.Fields", this must be dynamic also.
I'm suspect it's a defect and you are not getting anything for Request.Form.Keys that's matches Field. criteria.
your code works fine for me if I've a page class with dynamic Fields property

Creating Dynamic properties for object

I have a problem in creating dynamic objects. Please find the below code,
List<object> membersList = new List<object>();
foreach(var members in activityMembers){
dynamic myObject = new System.Dynamic.ExpandoObject();
myObject.MemberNumber = members.MemberNumber;
myObject.MemberName = members.Name;
foreach (var activity in members.ActivityList)
{
myObject.[activity.ActivityName] = activity.Minutes;
}
membersList.Add(myObject);
}
there inside the second foreach loop, i need to generate the properties to all activities. for example if there are 4 activities in members.ActivityList, then 4 properties needs to be generated for object.
myObject.Activity1 = 10;
myObject.Activity2 = 20;
myObject.Activity3 = 30;
myObject.Activity4 = 40;
How can i do this? What i did wrong here?
Regards,
Karthik.
Remove the . when you are indexing the object i.e. change
myObject.[activity.ActivityName] = activityMinutes;
to
myObject[activity.ActivityName] = activity.Minutes;
Actually this won't solve your problem straight away, it will compile fine but when you attempt to run it will throw a RuntimeBinderException as you can't index into a ExpandoObject directly. You need to cast it as a dictionary before iterating (that's effectively what it is) e.g.
var dict = (IDictionary<string, object>)myObject;
...
dict[activity.ActivityName] = activity.Minutes;
I suspect you need to treat the ExpandoObject as a dictionary for that part:
IDictionary<string, object> dictionary = myObject;
foreach (var activity in members.ActivityList)
{
dictionary[activity.ActivityName] = activity.Minutes;
}
That's the way of assigning properties to an ExpandoObject when you don't know the property name at compile-time.

Dynamically removing a member from Expando /dynamic object [duplicate]

Say I have this object:
dynamic foo = new ExpandoObject();
foo.bar = "fizz";
foo.bang = "buzz";
How would I remove foo.bang for example?
I don't want to simply set the property's value to null--for my purposes I need to remove it altogether. Also, I realize that I could create a whole new ExpandoObject by drawing kv pairs from the first, but that would be pretty inefficient.
Cast the expando to IDictionary<string, object> and call Remove:
var dict = (IDictionary<string, object>)foo;
dict.Remove("bang");
You can treat the ExpandoObject as an IDictionary<string, object> instead, and then remove it that way:
IDictionary<string, object> map = foo;
map.Remove("Jar");
MSDN Example:
dynamic employee = new ExpandoObject();
employee.Name = "John Smith";
((IDictionary<String, Object>)employee).Remove("Name");
You can cast it as an IDictionary<string,object>, and then use the explicit Remove method.
IDictionary<string,object> temp = foo;
temp.Remove("bang");

Delegates of types, or how to give a clumsy type a better name

In a project I'm working on, I use complicated Dictionary objects a lot. Often, there are a lot of declarations like:
var d1 = new Dictionary<string, Dictionary<int, List<string>>>();
var d2 = new Dictionary<Tuple<string, string>, List<object>>();
Between typecasts and passing parameters and what not, this gets annoying. What I'd like to do is something like this, using an imaginary keyword "typedel":
typedel ListDict = Dictionary<string, Dictionary<int, List<string>>>();
typedel PolyDict = Dictionary<Tuple<string, string>, List<object>>();
var d1 = new ListDict();
var d2 = new PolyDict();
So that I do not need to type the long Dictionary declarations every time - so what I want is something like defining shorthand abbreviations for a type name. How can I do this in the simplest way (using the fewest lines of code)?
class MyData : Dictionary<string, Dictionary<int, List<string>>>
{
}
You could also do this, but you would have to do it in every file which uses MyData, and that is probably suboptimial.
using MyData = Dictionary<string, Dictionary<int, List<string>>>;
For a "typedef" that you want to use a lot, you can just create a class that derives from the appropriate base class, as in #Ed S's answer:
class MyData : Dictionary<string, Dictionary<int, List<string>>>
{
}
However, this is not the same as what most people consider a typedef: you are introducing a new type, which has implications for things like reflection, typeof, the is operator, etc. The distinction may or may not matter to you, but it is there.
Within a single source file, however, you can use the second form of the using clause to do a real typedef:
using ListDict = Dictionary<string, Dictionary<int, List<string>>>();
using PolyDict = Dictionary<Tuple<string, string>, List<object>>();
In either case, while using a "typedef" will definitely save you typing, don't discount the benefits of seeing the types spelled out explicitly in your code. This is the same reason why articles such as this blog post recommend using List<Foo> over a custom FooCollection : List<Foo> -- with the explicit generic version you know what type of collection it is any what methods it exposes.
And, just for laughs...
static Func<T> Magic<T>(Func<T> f) { return f; }
static Func<T> Creator<T>() where T : new() { return () => new T(); }
...
var ListDict = Magic(() => new Dictionary<string, Dictionary<int, List<string>>>());
var PolyDict = Creator<Dictionary<Tuple<string, string>, List<object>>>();
var d1 = ListDict();
var d2 = PolyDict();

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