I have a list of objects and each object has a property that is a list of another object. Within this logic I'm casting the first object from a base class to one of it's inheriting classes.
It's this final list I want to make my changes to.
I've tried a few things already and I can see stepping through that the logic is executing but the finished product is always unchanged.
I've tried using linq:
Object1BaseObjectList
.Cast<Object1InheritedClass>()
.ToList()
.ForEach(e =>
e.Object2List
.ToList()
.ForEach(p => p.boolValue = true));
And I've tried some more conventional code:
foreach (Object1InheritedClass object1 in Object1BaseObjectList)
{
foreach (Object2Class object2 in object1.Object2List)
{
object2.boolValue = true;
}
}
Like I said the end result for both of these is no change. Anyone have any ideas as to what is going wrong here?
Just answering for the sake of closing this out. The information I provided was not enough to answer the question. Turns out the issue was being caused by the second list being declared as an IEnumerable. Changing it to a list corrected it. I'm assuming this was because IEnumerable wasn't creating a deep copy.
Related
I'm creating two objects and assign them with a data from IsolatedStorage.
But when I change one object the second one changes too. ( I think the problem may be the pointers are the same, but I can't solve it. )
private ArrayOfClsSimpleData lstUsers;
private ArrayOfClsSimpleData tmpLstUsers;
in class' globals
tmpLstUsers = IsolatedStorageHelper.GetObject<ArrayOfClsSimpleData>("users");
lstUsers = IsolatedStorageHelper.GetObject<ArrayOfClsSimpleData>("users");
The first status of the arrays:
Debug.Write(lstUsers.Count)
Output: 2
Debug.Write(tmpLstUsers.Count)
Output: 2
The counts are the same as expected. But, after I add an item to one list, the other list gets updated too and the counts are still same.
lstUsers.Add(new ArrayOfClsSimpleData());
Debug.Write(lstUsers.Count)
Output: 3
Debug.Write(tmpLstUsers.Count)
Output: 3
EDIT : IsolatedStorageHelper class is something to help to get objects, save object etc. that I do use for simplifying things, so just think it as getting objects from IsolatedStorage.
it is implemented like this:
public static T GetObject<T>(string key)
{
if (IsolatedStorageSettings.ApplicationSettings.Contains(key))
{
return (T)IsolatedStorageSettings.ApplicationSettings[key]; // return the object
}
return default(T); // if key doesn't exists , return default object
}
So it just gets it from IsolatedStorage.
If you don't know isolated storage you can see it from here
So, how can I fix the code so that I can change one without changing the other?
So, basically lstUsers and tmpLstUsers are references to the same object. All you have to do is to create a new one and copy content from the original. If you need a quick solution, then you can do it like this (code below). I just guess that ArrayOfClsSimpleData is some kind of array.
lstUsers = IsolatedStorageHelper.GetObject<ArrayOfClsSimpleData>("myKey");
tmpLstUsers = new ArrayOfClsSimpleData();
foreach (object user in lstUsers) // I don't know the type of objects in ArrayOfClsSimpleData, so I wrote 'object', but you should use the actual type
tmpLstUsers.Add(user);
The problem is that IsolatedStorage is just returning two pointers to the same data. So unless you copy the data, all changes will ultimately be to the same underlying data.
Think of it as two copies of your home address. Anything you change on your home affects all copies of your address since it is just an address and not the home itself.
What you will want to do is clone your object. Built in collections have clone or copy methods built in to do shallow copies, or if you built something yourself you will need to implement it yourself
The easiest way is to implement the IClonable interface and to use the clone method to achieve your copying.
https://msdn.microsoft.com/en-us/library/System.ICloneable.aspx
This basically involves going through and calling member wise clone for each complex object (which will copy all value types for you)
https://msdn.microsoft.com/en-us/library/system.object.memberwiseclone.aspx
I don't think cloning is necessary. Just create a new list instead of operating on the same instance. You can do that by calling ToList() on the returned instance:
lstUsers = IsolatedStorageHelper.GetObject<ArrayOfClsSimpleData>("myKey").ToList();
Can't you use the Clone() method of IClonable while fetching the object? looks like both list objects are getting same reference objects.
I have a strange thing happening with automapper.
Do someone have a clue why this code is returning a value for the InstitutionsImplantations field :
var result1 = new List<DataModel.Implantations>();
foreach (var c in collection)
{
DataModel.Implantations i = Mapper.Map<DataModel.Implantations>(c);
result1.Add(i);
}
var item1 = result1.Where(x => x.Nom == "Valdor").FirstOrDefault();
Console.WriteLine(item1.InstitutionsImplantations);
While this one (on the same collection), return null for InstitutionsImplantations :
var result2 = Mapper.Map<IEnumerable<DataModel.Implantations>>(collection);
var item2 = result2.Where(x => x.Nom == "Valdor").FirstOrDefault();
Console.WriteLine(item2.InstitutionsImplantations);
Facts :
The mapping done by autommaper on the IEnumerable is correct for the +/- first 300 items in the list, then after, some item collection have a "badly" mapped InstitutionsImplantations property.
InstitutionsImplantations property is an object "proxy" from a EF result.
do you have an idea why this is happening ?
Tx you !
Found the problem, using the automapper source code to see what was going on behind the scenes.
When automapper is processing the IEnumerable collection, its using a caching mechanism to avoid to have to remap an already mapped object that was present in the collection.
You would say, its fair, no reason to have the same object mapped to a different result.
But in my scenario, I forget to add that I was also using an AfterMap delegate at the mapping declaration.
In this AfterMap I was doing this (To avoid circular references problem) :
mappedItem.InstitutionsImplantations.Institution.InstitutionsImplantations = null;
This problem of this is that, I though that it was only impacting the result of the mapping (AfterMap delegate), and nothing else, but I was wrong it is also impacting the "Cache" being put in place !
This is not was I wanted, because in this case it did also impact all following mapping computing in the collection, using "Null" for the following mapped InstitutionsImplantations object, instead of brand new mapping.
My first solution was clean because the caching mechanism did not work between 2 "different" mapping.
And I didn't find an easy way to disable this collection caching mechanism inside automapper !
I'm new to the 4.0 framework (coming from 2.0), and I'm not entirely sure how to phrase this question so I figured it would be easiest to ask opposed to trying my luck with google.
Here's the scenario:
Let's say I have a collection of class "Wheel", and I have a second collection of class "Vehicle", where each vehicle object has a collection of "Wheel". My objective is to add every Vehicle's Wheels to my Wheel collection.
With the extension methods, is there another way to do this:
foreach(Vehicle v in vehicles)
{
wheels.AddRange(v.Wheels);
}
Or more specifically, in my actual use case there would only be one wheel (I need to add a specific member of each object in a collection to another collection):
foreach(Vehicle v in vehicles)
{
wheels.Add(v.Wheel);
}
I realize doing the above is pretty simple in itself, but for this project I'd like to use the additions to 3.5/4.0 wherever possible.
Thanks!
A little bit of LINQ will do the trick
wheels.AddRange(vehicles.SelectMany(v => v.Wheels));
Thanks Fourth, I should point out the other case. If there is just one wheel then Select will work:
wheels.AddRange(vehicles.Select(v => v.Wheel));
There is another approach:
vehicles.ForEach(v => { wheels.AddRange(v.Wheels); });
Or in case of one wheel:
vehicles.ForEach(v => { wheels.Add(v.Wheel); });
I have this code which, on the front-end, will create dependent selectboxes (subcategories are dependent on the category) using LINQ:
foreach (var cat in (from category in KB.Categories
orderby category.name
select category)) {
this.categories.Add(cat.id, cat.name);
}
foreach (var sub_cat in (from subcategory in KB.SubCategories
orderby subcategory.name
select subcategory)) {
this.subcategories.Add(sub_cat.id, sub_cat.name);
if (!this.subcategoryCategory.containsKey) {
this.subcategoryCategory.Add(sub_cat.category_id, new ArrayList());
}
// I'd like to put the sub_cat_id at the end of the arraylist
// for the category_id, but this line doesn't seem to work
//this.subcategoryCategory[sub_cat.category_id] = sub_cat.id;
}
How can I do this?
Perhaps there a way to build a giant JSON object instead of the three variables (categories, subCategoryCategory, subcategories)?
Is there a better/different way to do this that I've completely missed?
P.S. Coming from a different programming paradigm, I'm not doing this in the standard ASP.NET (webforms or MVC) way, but I am using codebehind to generate the values.
It looks like you actually want a Lookup, e.g.
var subcategories = KB.SubCategories.ToLookup(subcat => subcat.id,
subcat => subcat.name);
However, it's not really clear given that you've got subcategories, subcategoryCategory and categoies, all of which are instance variables which you haven't shown us the type for... and your if clause doesn't specify which key it's trying to use. It's all a bit confused at the moment...
My guess is that you should look at ToLookup and also ToDictionary, which are made for this sort of thing.
JSON.NET might solve this problem, with its ability to convert JSON objects to C# and back. See this SO question for an example.
I have a setup where I used Linq2SQL inheritance. To make queries easier, I expose the derived types in the DataContext as well, like the following:
public IQueryable<Derived> Derivations
{
get { return Bases.OfType<Derived>(); } // filter list on type
}
Calling this works perfectly, and I can see the SQL being correctly generated. The backing type is DataQuery<T>.
The problem comes in when I assigning this IEnumerable to a datasource (either a control or a BindingSource).
From what I can see, the DataQuery object is queried for an IListSource. And it happily supplies this. Then it proceeds to make a BindingList, which fails as the type parameter of the 2 arguments supplied (IEnumerable<Derived> and Table<Base>) does not match. It raises an exception of MissingMethod as the constructor cannot be found.
The simple workaround is just to call ToList() on the IQueryable<Derived> before assigning to the datasource and then it works, but this is quite tiring.
Any suggestions to handle this without 'loosing' the IQueryable?
Thanks
leppie
UPDATE:
The bug has now been reported to MS. More details here. Thanks Marc!
Confirmed. Looks like a bug to me; you should log it on Connect. The team are fixing LINQ-to-SQL bugs, so it might not be ignored. For now, use .ToList() etc.
Sample code:
using (var ctx = new MyDataContext())
{
var qry = ctx.BaseEntities.OfType<DerivedEntity>();
IListSource ls = (IListSource)qry;
IList list = ls.GetList(); // boom
/* Constructor on type
'System.Data.Linq.Provider.DataBindingList`1[snip]'
not found.*/
}
I had the same issue (still not fixed MS guys!).
To keep the IQueryable I did a .Cast<object>() when assigning to the datasource (i use it to output a xls file from any L2S table i want in a DynamicData website).