I'm writing a custom deserializer that will deserialize a list by deserializing each of the individual objects in the collection and then putting it together.
Basically my code looks like this:
//myField is a FieldInfo that represents the field we want to put the data in
//resultObject is the object we want the data to go into
List<Object> new_objects = new List<Object>();
foreach (String file_name in file_name_list)
{
Object field_object = MyDeserialization(file_name)
new_objects.Add(field_object)
}
myField.SetValue(resultObject, new_objects);
But this gives an error on the SetValue because (for example) I am trying to put a List(Object) into a List(Int32). Note that this problem only occurs with collections. The following code:
Object new_object = MyDeserialization(file_name)
myField.SetValue(resultObject, new_object)
works just fine provided that the runtime type of the result of MyDeserialization(file_name) is actually compatible with the type of myField. What is the problem here, and is there a way to make the collection deserialization work? (I've tried replacing the List(Object) declaration with myField.FieldType and that won't even compile.
Collections do not offer covariance... a List<int> simply isn't a List<object> (or v.v.). As such, you need to identify the T, for example like so (using the FieldInfo.FieldType) - and create the right type of list in the first place.
For convenience, once created it may be simpler to use the non-generic IList interface:
Type listType = typeof(List<>).MakeGenericType(itemType);
IList list = (IList)Activator.CreateInstance(listType);
list.Add(...); // etc
However; I must stress - writing a full (and robust) serializer is a lot of work. Do you have a specific reason? Many of the inbuilt serializers are pretty good - for example DataContractSerializer - or 3rd party, such as Json.Net, and (if I do say so myself) protobuf-net.
The problem is that .NET can't know that your List is actually a List. The following code should work:
//myField is a FieldInfo that represents the field we want to put the data in
//resultObject is the object we want the data to go into
List<MyType> new_objects = new List<MyType>();
foreach (String file_name in file_name_list)
{
Object field_object = MyDeserialization(file_name)
new_objects.Add((MyType)field_object)
}
myField.SetValue(resultObject, new_objects);
For Fun Linq Extra Credit (assuming file_name_list is IEnumerable):
myField.SetValue(resultObject, file_name_list
.Select(s => MyDeserialization(s))
.Cast<MyType>()
.ToList());
Related
I have a dynamic type in C# (Content, a type that inherits DynamicObject). It wraps an inner JSON object containing the data. In TryGetMember I return the requested properties from this inner JSON object. This works just fine in case of simple types (e.g. an int or string property), because .Net converts those values correctly.
But I want to use properties with more complex types:
dynamic content = Content.Load(id);
IEnumerable<Book> bookList = content.Books;
The problem is that in TryGetMember of my class I have no way to know the type that I should convert to (in this case the IEnumerable Book), because binder.ReturnType is always Object. According to this article, this is the normal behavior:
Determining the expected type of a DynamicObject member access
But I find this very hard to believe: how is it possible that the API does not let me know the target type? This way I will have to force developers to use the method syntax to specify the type explicitely:
IEnumerable<Books> bookList = content.Books<IEnumerable<Book>>();
...which is ugly and weird.
You could store Type data alongside the JSON serialized data, but that seems like a rather inefficient method of accomplishing what you're trying to do. If your content isn't truely dynamic (e.g., the content changes, but the basic schema of the object is the same), you could just have precompiled classes for each JSON object type, and serialize the JSON into that class once you receive the data. This way, all of the type data would already be recognized by the compiler at runtime.
It turns out that this is not possible indeed. I ended up creating an extension method (defined in two forms: for dynamic collections and JArrays). That way I can at least get a collection of my Content class and all of the following solutions work:
One line, but a bit long
var members = ((IEnumerable<dynamic>)group.Members).ToContentEnumerable();
Separate lines
IEnumerable<dynamic> members = adminGroup.Members;
foreach (dynamic member in members.ToContentEnumerable())
{
//...
}
Using the method call syntax of the extension method (a bit unusual).
var members = ContentExtensions.ToContentEnumerable(group.Members);
I am trying to get the actual object that is contained within a list that itself is contained within a task.
e.g. method has the following signature e.g.
public async Task<List<Dictionary<string,object>>> GetData()
i am currently using something like this:
var member = type.GetMembers()[0];
var returntype = member.ReturnType.GetGenericArguments();
var temp = member.ReturnType.GetGenericArguments()[0];
if (temp.GetGenericArguments().Count() > 0)
{
temp.GetTypeInfo().GetGenericArguments();
var innerttype = temp.GetGenericArguments()[0].FullName;
}
Currently the above code (which is not complete but just an extract from actual code) return system.object as fullname instead of Dictionary.
Any suggestions to solve this are welcome.
If you declare your dictionary to be of type <string, object> and and only ever insert objects inside it and not something higher up in the graph, you'll only ever get object typed objects out of it.
If you're storing all kinds of things in there and need to get their concrete type so you can interact with them, try to make them all conform to an interface first. Then, put the interface type in there replacing "object." If that doesn't work you can use generics. However, you'll still need to know the type ahead of time in order to be able to interact with it.
If you really have no idea what's in there and want to dig into it dynamically, that's precisely what Reflection was built for. You could also look into the dynamic type.
OK. I'm trying to take a List<Product> and pass it into a method that takes a generic List<object> and loops over them to create a List<dynamic> via reflection. This method needs to be able to handle lists of other objects (ie: Item, Customer, Package, etc).
The idea is then so that I'll have a generic list of dynamic that I could send via JSON across the wire.
How can I make this happen?
The simplest approach is to just use LINQ to build a new list. Given that you're using .NET 4, you've got covariance available to you, so you can use:
List<object> foo = products.ToList<object>();
Or even just:
List<object> foo = new List<object>(products);
You can't pass the existing list because a List<Product> simply isn't a List<object>.
Of course if you could change your method to accept an IEnumerable<object> instead, that would work fine due to covariance. That may be feasible if you're only trying to read from the parameter collection.
Mind you, it's not clear why you need to then use reflection to create a List<dynamic> - what's your method actually doing? Why can't you just use:
List<dynamic> foo = new List<dynamic>(products);
I'm trying to create objects dynamically but I don't know how to. What I need is, I have a class for that object, and objects properties are stored in the database. Then I'll need to compare the properties of each object to get the desired result.
So I need to dynamically create objects on the fly with the properties loaded from database.
I don't think you need to create objects dynamically, just create one statically that matches your db schema with the property details, then you can compare the values of the properties across rows, or within an instance of your object.
I have been working on something similar to this. There are several things:
Include the System.Reflection namespace
Create an object dynamically using Activator
Get the object properties using the myObjectType.GetProperties() method
Here is an example of a generic object creation function using the above methods:
using System.Reflection;
public static Item CreateItem<Item>(object[] constructorArgs, object[] propertyVals)
{
//Get the object type
Type t = typeof(Item);
//Create object instance
Item myItem = (Item)Activator.CreateInstance(t, constructorArgs);
//Get and fill the properties
PropertyInfo[] pInfoArr = t.GetProperties();
for (int i = 0; i < pInfoArr.Length; ++i)
pInfo.SetValue(myItem, propertyVals[i], null); //The last argument is for indexed properties
return myItem;
}
Of course the above example assumes that the values in the property value array are arranged correctly, which is not necessarily the case, but you get the idea.
With the PropertyInfo class you can get properties, get property names, get attributes associated with the properties, etc. Powerful technology. You should be able to do what you need with the above info, but if not let me know and I will add more info.
If you have a number of objects you want to instantiate from database values it can be done something like this.
//database code goes here, results go in results
List<ClassName> l = new List<ClassName>()
foreach(Row r in results){
l.Add(new ClassName(){ClassProperty1 = r.Property1,ClassProperty2 = r.Property2});
}
Are you talking about Dictionary?
var dict=new Dictionary<string, string>();
dict.Add("property1", "val1");
dict.Add("property2", "val2");
var prop2val=dict["property2"];
Maybe Activator is what your looking for?
http://msdn.microsoft.com/en-us/library/system.activator.aspx
Check this class, compile in the realtime. But it's performance is not quite good.
http://msdn.microsoft.com/zh-cn/library/microsoft.csharp.csharpcodeprovider(VS.80).aspx
You could use reflection to dynamically build your objects:
Reflection msdn reference
I think that you want to retrieve rows from the DB and directly assign them to object given that the properties of the object are equivalent to the columns of DB table. If that what you mean then I believe you can't :)
Rob Conery did a small project called Massive that pretty much does what you're trying to accomplish. It's essentially a small ORM, in 400 lines of Dynamic C# 4.0 code.
Rob has been doing this kind of thing for quite some time with SubSonic, so you might find his approach with Massive quite interesting.
http://blog.wekeroad.com/helpy-stuff/and-i-shall-call-it-massive
Some of the code is explained here, with examples:
http://blog.wekeroad.com/microsoft/the-super-dynamic-massive-freakshow
I am having a lot of trouble with Reflection in C# at the moment. The app I am writing allows the user to modify the attributes of certain objects using a config file. I want to be able to save the object model (users project) to XML. The function below is called in the middle of a foreach loop, looping through a list of objects that contain all the other objects in the project within them. The idea is, that it works recursively to translate the object model into XML.
Dont worry about the call to "Unreal" that just modifes the name of the objects slightly if they contain certain words.
private void ReflectToXML(object anObject, XmlElement parentElement)
{
Type aType = anObject.GetType();
XmlElement anXmlElement = m_xml.CreateElement(Unreal(aType.Name));
parentElement.AppendChild(anXmlElement);
PropertyInfo[] pinfos = aType.GetProperties();
//loop through this objects public attributes
foreach (PropertyInfo aInfo in pinfos)
{
//if the attribute is a list
Type propertyType = aInfo.PropertyType;
if ((propertyType.IsGenericType)&&(propertyType.GetGenericTypeDefinition() == typeof(List<>)))
{
List<object> listObjects = (aInfo.GetValue(anObject,null) as List<object>);
foreach (object aListObject in listObjects)
{
ReflectToXML(aListObject, anXmlElement);
}
}
//attribute is not a list
else
anXmlElement.SetAttribute(aInfo.Name, "");
}
}
If an object attributes are just strings then it should be writing them out as string attributes in the XML. If an objects attributes are lists, then it should recursively call "ReflectToXML" passing itself in as a parameter, thereby creating the nested structure I require that nicely reflect the object model in memory.
The problem I have is with the line
List<object> listObjects = (aInfo.GetValue(anObject,null) as List<object>);
The cast doesn't work and it just returns null.
While debugging I changed the line to
object temp = aInfo.GetValue(anObject,null);
slapped a breakpoint on it to see what "GetValue" was returning. It returns a "Generic list of objects" Surely I should be able to cast that? The annoying thing is that temp becomes a generic list of objects but because i declared temp as a singular object, I can't loop through it because it has no Enumerator.
How can I loop through a list of objects when I only have it as a propertyInfo of a class?
I know at this point I will only be saving a list of empty strings out anyway, but thats fine. I would be happy to see the structure save out for now.
Thanks in advance
I'm assuming that the actual value is not a List<object> but is something like a List<string> or List<int> or some other type that isn't exactly object?
If so, then the reason that the cast is failing is because generic classes are neither co- nor contravariant.
In C# 4.0, however, you will be able to make the foreach loop work by casting to IEnumerable<object> because interfaces can be co/contravariant.
(Much) more information here: http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx
Edit:
Thinking about it, you don't need generic variance here. List<T> implements the non-generic IEnumerable. This is all you need for the foreach loop to operate, and you only need the elements as type object so just cast it to an IEnumerable instead of List<object> and everything should work fine.
Generics and reflection don't mix well, especially for lists. I would strongly suggest using (non-generic) IList, or if that fails (some generic lists don't implement it), IEnumerable (since IEnumerable<T> : IEnumerable) and invoke the Add manually.
I feel your pain, really (I maintain an OSS serialization API).
In C# 3, you can't cast Lists<T> to other types of Lists<T> even when casting to something like List<Object>. It's explicitly not allowed even when casting to List.
In 4.0 variance changes a little with interfaces with the addition of the in and out keywords.
Here is a link to Eric Lippert explaining how and why this is the case.
http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx
Couldn't you just cast them to objects with OfType()?
List<object> listObjects = anObject.OfType<object>().ToList();
Update:
If the requirement wasn't for a List<object>, this would also work and involve no duplication of the list items:
var enumerableObjects = anObject.OfType<object>();