Array of dynamic | ExpandoObject | with a compressed initialize syntax - c#

Im trying to use DynamicObject in c#, and I needed an array of dynamic:
var d = new dynamic[];
which works fine.
EDIT : See ExpandoObject below.
But I also like to fill that array with some data with this compressed initialize new syntax:
var d = new dynamic[] {
new {
Name = "Some",
Number = 1010
},
new {
Name = "Other",
Number = 2010
}
}
But in that case all objects gets the non-dynamic type "object" and a loop through the items will give me an exception:
foreach (dynamic item in d)
{
#item.Name
#item.Number
}
Error : 'object' does not contain a definition for 'Name'. I guess I just initialize the array items the wrong way. How to add dynamic objects instead?
EDIT: New content:
I realize "dynamic" does not have the capability to dynamically add properties.
I better be using ExpandoObject which exposes all items in an an internal dictionary as properties. But unfortunately ExpandoObject does not seem to support this nice compressed create syntax, and the compiler complains:
var d = new ExpandoObject[]{
new ExpandoObject(){
Name="Nnn",
Number=1080
}
}
So the answer might just be : it's not possible.

Hopefully you do not really need dynamics
class Program
{
static void Main(string[] args)
{
var d = new[]
{
new
{
Name = "Some",
Number = 1010
},
new
{
Name = "Other",
Number = 2010
}
};
foreach (var item in d)
{
string s = #item.Name;
int n = #item.Number;
Console.WriteLine("{0} {1}", s, n);
}
}
}

I come a bit late but here is what i found about it :
if I can't initialise an ExpandoObject, how about initialising it with a dynamic type ?
so i did the following extension method
public static ExpandoObject CreateExpando(this object item)
{
var dictionary = new ExpandoObject() as IDictionary<string, object>;
foreach (var propertyInfo in item.GetType().GetProperties())
{
dictionary.Add(propertyInfo.Name, propertyInfo.GetValue(item, null));
}
return (ExpandoObject)dictionary;
}
I know it's far from ideal, but it's the best I could achieve for now, it works like this :
var myExpandoObject = new { Name="Alex", Age=30}.CreateExpando();

The open source framework Impromptu-Interface has a compressed initialization syntax that works with ExpandoObject.
dynamic #new = Builder.New<ExpandoObject>();
var d = #new.List(
#new.Expando(
Name:"Some",
Number: 1010
),
#new.Expando(
Name:"Other",
Number: 2010
)
);

Related

How to implement ForEach statement on Newtonsoft JArray

I need to cast JArray which I received from browser to list of MyType object. The problem is that I don't want to use .ToObject<> extension because object sended from browser can have missing or extra values and I cannot change deserializer. I wrote my own parser to receive data from single JObject. Usage:
foreach (var _object in _jarray)
{
using (var tp = new TokenParser(_object))
{
MyType test = new MyType()
{
id = tp.ConvertToInt("token_key")
};
}
}
What I want to do is something like this
_jarray.ForEach(_object => {
using (var tp = new TokenParser(_object))
{
MyType test = new MyType()
{
id = tp.ConvertToInt("token_key")
};
}
});
I don't want to cast elements like:
_jarray.Select(x =>
(int)["token_key"]
);
I tried to wrote this extension based on LINQ equivalent of foreach for IEnumerable<T> but it seems that Action requires T as parameter type. I don't need this because JArray is an array of JObject.
Is this possible to achieve?

How to get item type and members from list of object?

I have a
List<object> list = new List<object>();
while (myReader.Read())
{
string arrKablan = myReader["arrK_Title"].ToString();
string arrTotal = myReader["arrTotal"].ToString();
string _title = myReader["MF_Title"].ToString();
string _path = myReader["MF_Path"].ToString();
int _level = Convert.ToInt32(myReader["MF_Level"].ToString());
list.Add(new { title = _title, path = _path, kablanim = arrKablan, total = arrTotal, level = _level });
}
I need to select just items where level == 1
i tried
list = list.where(item => item.level == 1);
but i get an error
'object' does not contain a definition for 'level' and no extension method 'level' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)
i know that the compiler can get the type so he can know what it is "level".
how can i achieve this kind of select, without to define a class ?
You have two ways of fixing this:
Use a List<dynamic> instead of a List<object>. This will disable type checks. Drawback: This will disable type checks. :-)
Let the compiler infer the correct type of your list. To do this, have your data layer return a DataTable instead of a DataReader and then use LINQ to create the list:
var myList = (from drow in myDataTable.AsEnumerable()
select new {
kablanim = drow["arrK_Title"].ToString(),
total = drow["arrTotal"].ToString(),
...
}).ToList();
I can't see why you don't just make a concrete class:
public class Foo
{
public string Title { get; set; }
public string Path { get; set; }
// etc, etc
}
Then
List<Foo> list = new List<Foo>();
while (myReader.Read())
{
string arrKablan = myReader["arrK_Title"].ToString();
string arrTotal = myReader["arrTotal"].ToString();
string _title = myReader["MF_Title"].ToString();
string _path = myReader["MF_Path"].ToString();
int _level = Convert.ToInt32(myReader["MF_Level"].ToString());
list.Add(new Foo { Title = _title, Path = _path, /* etc, etc */ });
}
then you call becomes
list = list.Where(item => item.Level == 1).ToList();
(Note the additional ToList call required to make the list assignment valid)
Just for completeness, you can also do this. Create a function to get a value from any object using reflection:
private T GetValue<T>(object obj, string property)
{
return (T)obj.GetType()
.GetProperties()
.Single(p => p.Name == property)
.GetValue(obj);
}
And call it like this:
var filteredList = list.Where(item => GetValue<int>(item, "level") == 1);
You can get value of a property on anonymous class like this:
var anon = new { Level = "level", Time = DateTime.Now };
Type type = anon.GetType();
var props = type.GetProperties();
foreach (var propertyInfo in props)
{
if (propertyInfo.Name == "Level")
{
var x =propertyInfo.GetValue(anon);
}
}
I'm not sure if it is the best way to achieve that, but it is certainly possible.
You are adding object of anonymous class to the list. You can refer to this anonymous class field only inside the method you've defined it in and you should probably avoid adding it to the list, because there is now other way other then reflection or dynamic to access field of theese objects.
For example, you can access one of the elements like this:
var list = new List();
list.Add(new { field1 = "a", field2 = 2 });
list.Add(new { field1 = "b", field2 = 3 });
list.Add(new { field1 = "c", field2 = 4 });
dynamic o = list[1];
Console.WriteLine(o.field1);
Console.WriteLine(o.field2);
But you should be aware, that dynamic feature has a big overhead on every member access.
If you really want to use lambdas, you can rewrite
list = list.where(item => item.level == 1);
like this
var filtered = list.Where(item =>
{
dynamic ditem = item;
return ditem.Level == 1;
});
but this is a bad approach.
The other approach is to use reflection and rewrite this lambda like this
var filtered = list.Where(item =>
{
var field = item.GetType().GetField("level");
return (int)field.GetValue(item) == 1;
});
This is better than using dynamic because it has a smaller overhead, but can still be very costly.
Also it would probably be better to cache FieldInfo object outside of loop if your anonymous objects have same type. It can be done like this
var field = list.First().GetType().GetField("level");
var filtered = list.Where(item => (int)field.GetValue(item) == 1);
For performance reasons, Linq depends on metadata being available at compile time. By explicitly declaring List<object> you have typed the elements of this list as object which does not have a member level.
If you want to use Linq like this you have two options.
Declare a class with a level member and use it to type the collection
Declare an interface with a level member and use it to cast in the lambda expression
Option 1 is the preferred approach. Normally Linq is used with a database and the classes are generated by Visual Studio directly from the database. This is why nobody complains about the need for classes to supply metadata.
The following line creates anonymous class.
new { title = _title, path = _path, kablanim = arrKablan, total = arrTotal, level = _level });
You can't cast then your objects to anything meaningfull.
Objects don't have those properties.
You have to create a class by your own and use it.

Parsing complex JSON Object with C#

I have a JSON like this one:
{
"name" : "MyCustomName",
"my_node" : {
"name" : "my_node_name"
},
"dict1":"value1",
"dict2":"value2",
"dict3":"value3",
...
}
and an object:
class Node{
string value;
}
class Sample:IDictionary<string, string>{
Node node;
string name;
}
Node and Name in Sample class are always present.
The thing is I don't know how many "dictN" fields will be... and that's the point.
And the question is:
How to Deserialize that JSON to this Object?
Edit: apparently even with field names harmonized, your deserializer just can't cope with specific fields combined with general dictionary fields.
In which case, I'd just advise deserializing as a Dictionary<string, object> and building with the result:
var d = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(json);
Sample s = new Sample();
s.name = (string)d["name"];
Node n = new Node();
n.value = (string)((Dictionary<string, object>)d["my_node"])["name"];
foreach (var key in d.Keys.Except(new string[] { "name", "my_node" }))
{
s.Add(key, (string)d[key]);
}
INITIAL IDEA
The following is a dictionary serializer. It has one special case of not accepting empty string.
private void SerializePerinatalModel<T>(IDictionary<string, object> dataModel, T perinatalModel)
{
Type sourceType = typeof(T);
foreach (PropertyInfo propInfo in (sourceType.GetProperties()))
{
if (dataModel.ContainsKey(propInfo.Name))
{
// if an empty string has been returned don't change the value
if (dataModel[propInfo.Name].ToNullSafeString() != String.Empty)
{
try
{
Type localType = propInfo.PropertyType;
localType = Nullable.GetUnderlyingType(localType) ?? localType;
propInfo.SetValue(perinatalModel, Convert.ChangeType(dataModel[propInfo.Name], localType), null);
}
catch (Exception e)
{
// ToDo: log update value errors
}
}
}
}
}
but could be made null safe. It does deal with nullable types.
As JSON is essentially a dictionary type then iterating through the top level types should get you there.
This is written in haste so is only a sketch of an idea.
BETTER IDEA
Also try using
foreach (var item in JsonData.Where(m => m.Key.Substring(0,4) == "dict"))
{
// add item to collection
}
might also do the biz.
You can simply have the output in the form of Dictionary<string, object>, try this piece of code instead.
System.Web.Script.Serialization.JavaScriptSerializer s =
new System.Web.Script.Serialization.JavaScriptSerializer();
var nodes = s.Deserialize<Dictionary<string, object>>(jsonString);
var dictNodes = nodes.Where(w => w.Key.StartsWith("dict"));

Dynamic Sorting with a SerializableDynamicObject

I have a need to sort a collection of these based upon criteria determined at run-time.
I was using the code from this article to perform the sorting - originally my code used the dynamic class.
Then I hit issues with serialization over WCF so I switched to using a SerializableDynamicObject and now the sorting code breaks on the line:
PropertyInfo pi = type.GetProperty(prop);
with the error that SerializableDynamicObject does not have a property called "Name" - where "Name" was the value of prop.
I guess the simplest thing to do is to find an alternate way of serializing a dynamic type that the sorting algorithm works with. Any pointers in this direction would be appreciated!
I have looked at this example, but I get the error message:
The constructor with parameters (SerializationInfo, StreamingContext) is not found in ISerializable type
Here's some code using FastMember for this, which works for both reflection-based and dynamic-based objects (depending on what you pass to TypeAccessor.Create)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using FastMember;
namespace ConsoleApplication6
{
class Program
{
static void Main()
{
var list = new List<dynamic>();
dynamic obj = new ExpandoObject();
obj.Foo = 123;
obj.Bar = "xyz";
list.Add(obj);
obj = new ExpandoObject();
obj.Foo = 456;
obj.Bar = "def";
list.Add(obj);
obj = new ExpandoObject();
obj.Foo = 789;
obj.Bar = "abc";
list.Add(obj);
var accessor = TypeAccessor.Create(
typeof(IDynamicMetaObjectProvider));
string propName = "Bar";
list.Sort((x,y) => Comparer.Default.Compare(
accessor[x, propName], accessor[y,propName]));
foreach(var item in list) {
Console.WriteLine(item.Bar);
}
}
}
}
It may be worth mentioining that for reflection-based types, this does not use reflection on a per-item basis; all that is optimized away via meta-programming.
Marc Gravell's answer gave me the answer to complete this - I needed to implement a sorter that could handle multiple sort criteria, not known until runtime. I'm accepting Marc's answer, but posting this as someone may find it useful too.
There may be a more elegant way of achieving this, if so please let me know and I'll update the answer.
public class SerializableDynamicObjectComparer: IComparer
{
private readonly List<KeyValuePair<string, bool>> sortCriteria = new List<KeyValuePair<string, bool>>();
private readonly TypeAccessor accessor;
public SerializableDynamicObjectComparer(IEnumerable<string> criteria)
{
foreach (var criterium in criteria)
{
string[] sortCriterium = criterium.Split('.');
this.sortCriteria.Add(new KeyValuePair<string, bool>(sortCriterium[0],
sortCriterium.Length == 0
? sortCriterium[1].ToUpper() == "ASC"
: false));
}
this.accessor = TypeAccessor.Create(typeof (IDynamicMetaObjectProvider));
}
public int Compare(object x, object y)
{
for(int i=0; i< this.sortCriteria.Count; i++)
{
string fieldName = this.sortCriteria[i].Key;
bool isAscending = this.sortCriteria[i].Value;
int result = Comparer.Default.Compare(this.accessor[x, fieldName], this.accessor[y, fieldName]);
if(result != 0)
{
//If we are sorting DESC, then return the -ve of the default Compare result
return isAscending ? result : -result;
}
}
//if we get here, then objects are equal on all sort criteria.
return 0;
}
}
Usage:
var sorter = new SerializableDynamicObjectComparer(sortCriteria);
var sortableData = reportData.ToList();
sortableData.Sort(sorter.Compare);
where sortCriteria is an array of strings e.g.
new {"Name.DESC", "Age.ASC", "Count"}

Iterate over object fields in C#

Foo is a class with a lot of string fields. I want to create a method Wizardify that performs an operation on many of the fields of the object. I could do it like this:
Foo Wizardify(Foo input)
{
Foo result;
result.field1 = Bar(input.field1);
result.field2 = Bar(input.field2);
result.field3 = Bar(input.field3);
...
This is some easily generated code, but I prefer not to waste fifty lines on this. Is there a way to go over selected fields of an object? Note that there are four or five fields I want to work on in a different way and they should be excluded from the iteration.
try
foreach ( FieldInfo FI in input.GetType().GetFields () )
{
FI.GetValue (input)
FI.SetValue (input, someValue)
}
Though I would not recommend the reflection approach for known Types - it is slow and depending on your specific scenario could pose some permission issue at runtime...
This is what I have - it gives me a list (names) of all properties in my classes, that later I can work on with Reflection or "Expression trees":
private static string xPrev = "";
private static List<string> result;
private static List<string> GetContentPropertiesInternal(Type t)
{
System.Reflection.PropertyInfo[] pi = t.GetProperties();
foreach (System.Reflection.PropertyInfo p in pi)
{
string propertyName = string.Join(".", new string[] { xPrev, p.Name });
if (!propertyName.Contains("Parent"))
{
Type propertyType = p.PropertyType;
if (!propertyType.ToString().StartsWith("MyCms"))
{
result.Add(string.Join(".", new string[] { xPrev, p.Name }).TrimStart(new char[] { '.' }));
}
else
{
xPrev = string.Join(".", new string[] { xPrev, p.Name });
GetContentPropertiesInternal(propertyType);
}
}
}
xPrev = "";
return result;
}
public static List<string> GetContentProperties(object o)
{
result = new List<string>();
xPrev = "";
result = GetContentPropertiesInternal(o.GetType());
return result;
}
Usage: List<string> myProperties = GetContentProperties(myObject);
Loop through typeof(YourType).GetProperties() and call GetValue or SetValue.
Note that reflection is rather slow.
You could use the Dynamic Language Runtime to generate a lambda of the type Func. You'll just need to generate the lambda once (you can cache it away) and there'll be no reflection performance hit.

Categories

Resources