I'm trying to create an ArrayList of objects in C#. What I've tried so far is:
class POObject
{
public List<string> staticCustInfo;
public List<List<string>> itemCollection;
public int testInt;
}
POObject myObject = new POObject();
List<POObject> BatchList = new List<POObject>();
This is fine, except when I try to add an object to this list using:
BatchList.Add(item);
It gives me errors saying it can't find a corresponding method to add to the list. Any ideas? Thanks for the help.
What are you trying to store in your list? You declare a BatchList as containing POObjects, but then you're trying to add item, which is of what type? If you're adding things to this list that are not POObjects, you can declare it as either a non-generic list:
List BatchList = new List();
or as a generic list of objects:
List<object> BatchList = new List<object>();
But I suspect the real problem may be that you're trying to add the wrong type of item to your collection. Can you show us how you get your item variable?
If you declare that BatchList is of type List<POObject>, then that means the List can only contain objects of type POObject. That's what the type parameter is for. You cannot add strings, ints, or any other arbitrary objects to this list, only POObjects (and descendents of POObject).
If you take a look at the intellisense, you will see that Add's signature is this:
void Add(POObject item)
If you really want a list that contains arbitrary items, then use an ArrayList, which is not a generic type and can accept any type of object. However since C# is such a strongly typed language, wanting arbitrary lists like this is usually a code smell.
Related
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 need to find out if a Type I'm working with is a Generic 'container', for example if I have a List<int> I need to check if I'm working with a List (I know how to get whether I'm working with an int), how would I do that? (I'm thinking Reflection). Another example, I have a class called StructContainer<T>, I need to find the word (name) 'StructContainer', I'm not too bothered with what 'T' is, using reflection I get StructContainer'1, would hate to have to do some string splitting etc /EDIT: Just to explain further, StructContainer<int> I need 'StructContainer', Tuple<int> I need 'Tuple', List<int> I need 'List' and so forth
Your first question can be achieved in multiple ways:
Check whether your object implements IEnumerable<T>: yourObject is IEnumerable<int>. This only works if you know the type of the object in the container (int in this case)
Use the same solution I described below, just change StructContainer to List.
As to your second question, you can do this:
var yourObject = new StructContainer<int>();
var yourType = yourObject.GetType();
if(yourType.IsGenericType &&
yourType.GetGenericTypeDefinition() == typeof(StructContainer<>))
// ...
string type = yourObject.GetType().Name.Split('`')[0];
why does
List<Object> objectList; = some objects
List<Object> getList()
{
return objectList; //or return new List<Object>(objectList);
}
return a list with all items referenced to the original list's items?
Thanks.
In the first case you just return a reference to the list.
In the second case (new List<Object>(list)) the objects are not copied: only the references are copied! You have to clone each item in the collection to return a deep copy of the list.
EDIT:
Iterate through your whole list and create a copy of each of your objects and put them into a new list.
See this for creating deep copies of custom objects. I would suggest not to use the interface ICloneable. Make some research to learn why. :)
It is a reference
You're returning a reference to ObjectList. : )
AboutTheConstructor:
From MSDN: List<(Of <(T>)>)(IEnumerable<(Of <(T>)>)) Initializes a new instance of the List<(Of <(T>)>) class that contains elements copied from the specified collection and has sufficient capacity to accommodate the number of elements copied.
Basically, because List<> and Object are reference types. If you read up on reference/value types in C# here: http://msdn.microsoft.com/en-us/library/3ewxz6et(v=VS.100).aspx it should make sense to you.
if you are using a custom object, Implement the ICloneable interface on the object.
Then, when you are returning your list, clone the objects into a new list. When you pass your old list into the constructor of your new list, you are passing references to all the objects in the original list, unless they are value type (string, int, etc)
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>();
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());