List<> collection members changing when they aren't supposed to - c#

I have a List that I have populated in the main method of a console project. I pass this population to a method which is meant to take two members of the population and decompose and recombine them in a way to create two new unique members which will later be added to the population.
However when I manipulate the two original members to create the two new unique members the two original members change with in the initial population (hence altering the initial population).This means that when I go to add the new members I get duplication of entries into the List.
I'm not doing anything overly complicated I think I am just doing something stupid.
Does any one have any insight as to why this is happening ?
Here is the method that gets called to choose to initial two members of the population:
public static List<Chromosome<Gene>> runEpoch(Random rand, List<Chromosome<Gene>> population, SelectionMethod selectionMethod)
{
int populationSize = population.Count;
int selectionCount = (int)Math.Truncate((population.Count * 0.75));
if (selectionMethod == SelectionMethod.Tournament)
{
for (int i = 0; i < selectionCount; i++)
{
Chromosome<Gene> parent = selection.runTournament(rand, population);
Chromosome<Gene> parentTwo = selection.runTournament(rand, population);
//Checks for the presence of incestuous mating. In some cases incestuous mating causes a stack overflow to occur that the program can not recover from
if (parent != parentTwo)
{
//where runGeneOperators calls the crossOver method directly
offSpring = runGeneOperators(rand, parent, parentTwo);
}
else
{
i--;
}
}
}
else
{
//NSGAII
}
//fixPopulation is meant to sort and remove any excess members
return fixPopulation(rand, population, selectionMethod, populationSize); ;
}
And here is the code that is creating the two new unique members :
public List<Chromosome<Gene>> crossOver(Random rand, Chromosome<Gene> parentOne, Chromosome<Gene> parentTwo)
{
List<Chromosome<Gene>> offSpring = new List<Chromosome<Gene>>();
int crossPtOne = rand.Next(0, parentOne.Length);
int crossPtTwo = rand.Next(0, parentTwo.Length);
if ((crossPtOne == 0) && (crossPtTwo == 0))
{
offSpring.Add(parentOne);
offSpring.Add(parentTwo);
return offSpring;
}
else
{
GeneNode<Gene> fragOne = parentOne.Children[crossPtOne];
GeneNode<Gene> fragTwo = parentTwo.Children[crossPtTwo];
crossOverPoint = crossPtOne;
GeneNode<Gene> genotype = performCrossOver(parentOne.Genotype, fragTwo);
success = false;
parentOne.repair(genotype);
offSpring.Add(parentOne);
crossOverPoint = crossPtTwo;
GeneNode<Gene> genotype2 = performCrossOver(parentTwo.Genotype, fragOne);
success = false;
parentTwo.repair(genotype2);
offSpring.Add(parentTwo);
}
return offSpring;
}
private GeneNode<Gene> performCrossOver(GeneNode<Gene> tree, GeneNode<Gene> frag)
{
if (tree != null)
{
if (crossOverPoint > 0)
{
if (!success && tree.Left != null)
{
crossOverPoint--;
tree.Children[0] = performCrossOver(tree.Left, frag);
}
}
if (crossOverPoint > 0)
{
if (!success && tree.Right != null)
{
crossOverPoint--;
tree.Children[1] = performCrossOver(tree.Right, frag);
}
}
}
if (!success)
{
if (crossOverPoint == 0)
{
success = true;
return frag;
}
}
return tree;
}

In C#, objects are reference types, meaning adding something to a collection only adds a reference. If you manipulate a variable with the same reference (in your case, the "original" objects), all references pointing to that object will be changed as well. You need to copy the object somehow to have a different object and manipulate that.

To manipulate your collection and objects within it without altering it, you need to do a deep clone of the collection and it's containing objects, so you can alter list A without altering clone B. If you just wish to change some object inside the list you need to make a deep clone of the object inside the list and then alter the deep clone. This will make sure that your original is not altered.
The IClonable interface should be implemented on your objects to make them clonable.
EDIT: Per Henk's Comments, you should just implement your own copy method without implementing the IClonable interface, as per this article.
Cloning of objects comes in two forms, deep and shallow.
Shallow: This form of cloning creates a new object and then copyies the nonstatic fields of the current object to the new object. If a field is a value type, a bit-by-bit copy of the field is performed. If a field is a reference type, the reference is copied but the referred object is not; therefore, the original object and its clone refer to the same object.
Deep:This creates a new object and clones all data members and fields of the clonable object. This object references X2 where the original will reference X.
Here a post from SO that might assist you in cloning.

Item 1 - Keep your list references private
From a API perspective, an object should never give out the reference to its internal list. This is due to the issue you have just found, whereby some other consumer code can go ahead and modify that list as it sees fit. Every reference of that list, as shared around, including the 'owning' object, has their list updated. This is usually not what was intended.
Further, the responsibility is not on the consumer to make its own copy. The responsibility is on the owner of the list to keep its version private.
It's easy enough to create a new List
private List<Gene> initialGeneList;
public List<Gene> InitialGenes
{
get { return new List<Gene>(initialGeneList); } // return a new list
}
This advice also includes passing your own list to another class/method.
Item 2 - Consider using an immutable object
Without going too much into reference vs value types, what this means is treat the object like a value type, and whenever you have an operation, return a new object instead of mutating the original.
Real value types in .net, like integers and DateTimes have the semantic of copy on assignment. e.g. When you assign, a copy is created.
Reference types can also behave like value types, and strings are good example. Many people make the following mistake, because they fail to realize the value-type semantics of System.String.
string s = "Hello World";
s.Substring(0,5); // s unchanged. still 'Hello World'
s = s.Substring(0,5); // s changed. now 'Hello'
The string method Substring() doesn't mutate the original object, but instead returns a new one containing the result of the operation.
Where appropriate, the use of immutable objects can make the program a lot easier to understand and can reduce defects considerably.
When implementing immutable objects, one caveat is the likely need to implement value equality for comparing two objects (by overriding Equals). Objects are reference types, and by default two objects are equal if their references are equal.
In this snippet, the values of the objects are equal, but they are different objects.
string s1 = "Hello";
string s2 = string.Concat("He","l", "lo");
bool equal = s1.Equals(s2);
bool referenceEqual = object.ReferenceEquals(s1, s2);
// s1 == s2 => True, Reference Equal => False
Console.Write("s1 == s2 => {0}, Reference Equal => {1}", equal, referenceEqual);

Related

Why does modifying one session variable also modify a different session variable?

I have a weird problem. One of my variables is changed via this function (code below). I don't know how it is possible. I want to change Session["p_skok"], but in some way, variable Session["z_skok"] is also changing.
protected void oblicz_parametry()
{
List<string> lista_odnosnik_wartosc = (List<string>)Session["p_wartosc"];
List<Type> lista_odnosnik_typ = (List<Type>)Session["p_typ"];
List<bool> lista_odnosnik_inkrementacja = (List<bool>)Session["p_inkrementacja"];
List<int> lista_odnosnik_nr = (List<int>)Session["p_nr"];
List<int> lista_odnosnik_skok = (List<int>)Session["p_skok"];
List<int> lista_odnosnik_skok_pomocnicza = (List<int>)Session["z_skok"];
if (Session["iteracja"] != null)
{
for (int i = 0; i < lista_odnosnik_inkrementacja.Count(); i++)
{
if (lista_odnosnik_skok[i] == 0 && lista_odnosnik_inkrementacja[i] == true)
{
int zwieksz = lista_odnosnik_nr[i];
//if (lista_odnosnik_typ[i].ToString() == "int")
//{
int zm_pomocnicza = Convert.ToInt32(lista_odnosnik_wartosc[i]) + lista_odnosnik_nr[i];
lista_odnosnik_wartosc[i] = zm_pomocnicza.ToString();
//}
lista_odnosnik_skok[i] = lista_odnosnik_skok_pomocnicza[i] + 1;
}
lista_odnosnik_skok[i]--;
}
Session["p_wartosc"] = lista_odnosnik_wartosc;
Session["p_skok"] = lista_odnosnik_skok;
}
else
{
Session["iteracja"] = 1;
Session["p_wartosc"] = Session["z_wartosc"];
Session["p_inkrementacja"] = Session["z_inkrementacja"];
Session["p_nr"] = Session["z_nr"];
Session["p_skok"] = Session["z_skok"];
oblicz_parametry();
}
}
I did some debugging and found out that decreasing happens because of lista_odnosnik_skok[i]--; part of the code. Do you know what might be happening?
It's a combination of two things. In the else clause you have this:
Session["p_skok"] = Session["z_skok"];
Once you do that, those two variables refer to the same list. Now whatever you do to one list, you're doing to the other, because they're the same list.
Then you're setting Session["iteracja"] = 1;, which means next time the condition if (Session["iteracja"] != null) will be true.
Within that condition you're making changes to lista_odnosnik_skok, which is Session["p_skok"] which is the same list as Session["z_skok"];.
To solve it, don't set the one session variable equal to the other. You could do this:
var existingList = (List<int>)Session["z_skok"];
Session["p_skok"] = new List<int>(existingList);
Now you've created a new list that contains the same elements as the original list. They're two distinct lists, so modifying one doesn't modify the other.
It's worth noting that this works because int is a value type, not a reference type, so when you add the values from one list to the other list you're creating new values. You can modify the values in one list without modifying the others.
If the items in the list were reference types you'd still have a similar problem. You'd have two lists (good) but they would both contain references to the same objects (probably bad). You'd be able to add or delete on one list without modifying the other list, but modifying the item in the list would modify the item in the other list, because they're both the same item.
But again, that's just for explanation. The list contains int so in this case it's not a problem.
It might also be easier to follow if you read everything you need out of Session into variables at the beginning, and then save everything back to Session at the end. That way you're not trying to keep track of both local variables and session variables at the same time. It's confusing, which means it's easier to make mistakes.
You might even find it helpful to define a new class that contains all of these lists. Retrieve that one object from session (if it's null create new one), and when you're done working with it, save the whole object. It's the same as what you're doing, but now you're only dealing with one session variable instead of five, and it's even easier to keep track of.
At some point in the lifecycle of your program you set these two session variables equivalent:
Session["p_skok"] = Session["z_skok"];
This line of code is in the else block. The session will survive for a long time, perhaps hours:
After this line of code has run they will both refer to the same list object in memory and any changes inflicted on the contents of either Session["p_skok"] or lista_odnosnik_skok, or Session["z_skok"]; or lista_odnosnik_skok_pomocnicza will all have the same effect because they're all references to the same List<int>

Changing one property in multidimensional array changes other array's properties too

I have a multidimensional array called SensorGetResult. In some cases this array can have a single array in it. If that happens, I must copy this one array and add it again, so I must have 2 arrays now. Then I need to change these array's dateTime property. This is my code:
var helperArray = sensorGet.SensorGetResult[0];
sensorGet.SensorGetResult.Add(helperArray);
sensorGet.SensorGetResult[0].dateTime = end; //It works correctly including this line
sensorGet.SensorGetResult[1].dateTime = start; //At this line both array's dateTime property changes
Why can't I assign dateTime properties to each array individually?
It looks like you are using a reference type for your helperArray.
When the following code executes:
var helperArray = sensorGet.SensorGetResult[0];
sensorGet.SensorGetResult.Add(helperArray);
What actually happens is you take a the first element of SensorGetResult which is a reference to the object (which I believe you intend to copy) and append the reference to the list thus resulting in a list which has two references to the same object in the memory.
If you want it to make a copy of the object, you have to implement that by yourself. Usually this means creating a new object of the same type and copying all the properties.
var objectToCopy = sensorGet.SensorGetResult[0];
var helperArray = new WhatEverTypeIsYourHelperArray {
Property1 = objectToCopy.Property1,
Property2 = objectToCopy.Property2,
// etc.
};
sensorGet.SensorGetResult.Add(helperArray);
But you have to be aware if any of the properties is furthermore a reference type, you need to do this recursively for all the properties.
If WhatEverTypeIsYourHelperArray is type you own, you could utilize Object.MemberwiseClone method and make it all easier for yourself. You can do this by implementing a method like the following. As a note, MemberwiseClone is a protected method hence the need of a new method in your class.
public WhatEverTypeIsYourHelperArray Clone() {
return (WhatEverTypeIsYourHelperArray)this.MemberWiseClone();
}
But even the MemberwiseClone() method doesn't copy reference types for you, rather just copies the pointers to the objects which means that all the properties of reference type of both the original and the cloned object will point to the same objects in the memory.
SensorGetResult row seems to be a reference type.
So when you wrote
var helperArray = sensorGet.SensorGetResult[0];
sensorGet.SensorGetResult.Add(helperArray);
you actually said that new row in SensorGetResult will point to the same object as the first one.
You can implement method like below:
public SensorGetResultRow Clone()
{
return new SensorGetResultRow (this.field1, this.field2, etc...)
//or if you use parameterless constructor
return new SensorGetResultRow ()
{
field1 = this.field1
//etc.
}
}
and use it:
var helperArray = sensorGet.SensorGetResult[0].Clone();

Comparing two objects' properties simply in c#

I have a class with lots of properties. A shallow copy is enough to fully replicate the object.
I need to compare an object just to check if it contains exactly the same values as another.
My ideas:
The first and most obvious solution is just to create a huge method block that compares each property, one after the other.
The second would be to serialize each object and hash the file or do some sort of md5 checksum on it. (Would this actually work?)
The third is to do some sort of reflection on the object, which would automate the first option, but create an added level of complexity.
Speed isn't really an issue.
I'm interested to hear thoughts, or any other methods I am missing to do such a thing.
Edit:
Thanks all. My solution (Modified to now be recursive on generic items):
public static bool IsSame<T>(T objA, T objB)
{
var type = typeof(T);
var properties = type.GetProperties();
foreach (var pi in properties.Where(a => a.CanRead))
{
if (pi.Name == "Item")
{
var piCount = properties.FirstOrDefault(a => a.Name == "Count");
int count = -1;
if (piCount != null && piCount.PropertyType == typeof(System.Int32))
count = (int)piCount.GetValue(objA, null);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
dynamic child1 = pi.GetValue(objA, new object[] { i });
dynamic child2 = pi.GetValue(objB, new object[] { i });
return IsSame(child1, child2);
}
}
}
else
{
var val1 = type.GetProperty(pi.Name).GetValue(objA, null);
var val2 = type.GetProperty(pi.Name).GetValue(objB, null);
if (val1 != val2 && (val1 == null || !val1.Equals(val2)))
return false;
}
}
return true;
}
Most serializers are designed to ensure that data retains its integrity during serialization and deserialization, not to produce a consistent serialized format. I would avoid using serialization for this purpose.
You may consider implementing IEquatable, to have each instance capable of comparing itself with instances of the same type. Or a class do do the comparisons for you that implements IEqualityComparer. How they do this comparison may be the 'big method' that compares properties one after the other, or uses reflection.
Reflection can be a fairly quick and simple way to achieve your goal but can cause problems down the line (for example if someone adds a property to your type that should not be included for comparing equality), but obviously the converse is also true (someone adds a property that should be checked for equality, but the equality comparison isn't updated). Which approach you use should generally be decided by how comfortable the team is with each approach in tandem with the context in which the class will be used.
In your case I'd probably recommend using the reflection based approach since you wish to check the result of a shallow clone operation, so all properties should be equal.
As an aside, I'd recommend using the MemberwiseClone method to create the clone, which would lessen the need for such stringent tests.
The third option (reflection) would be the slowest, but it would also be the most robust/testable.
The hash code would be very similar to the first option, since you would have to call all of your member variables, so 1 and 2 would require you to update your .Equals(obj) and .GenerateHash() methods every time you modify your member variable lists.
Here is some code to get you started:
foreach (FieldInfo field in this.GetType().GetFields())
{
if (o[field.Name] == null)
{
if (!field.GetValue(this).Equals(o[field.Name]))
return false;
}
else
{
return false;
}
}
return true;
Another thought is that if the properties return simple value types you could group them into immutable value types of their own. For instance, if you have a customer with properties string Address1 string Address2 string City string State string Zip, you could create a value type Address that implements its own equality comparer and use that.
Not sure if this applies to your situation, but I've found that when I have a class with a lot of properties, it is often possible to do this, and it tends to make my classes simpler and easier to reason about.
If you serialize you have to specify the serialization order on each Field/Property to ensure that all data is serialized int the same order. But all you would achieve is to implement GetHashCode() in an external class.
GetHashCode() has some examples on how to override it, so look there first.
If your class has a lot of fields, and you don't want to write all the code by hand. You could use reflection to autogenerate the code. If your class changes from time to time then you could create a partial class with the GetHashCode() implementation in a T4 template.

Strange Reflection problem - can't get it

please help me understand what's going on in here and whether it should work like that ?
I have a generic list of objects from a CMS:
For example List<MyCMS.Articles.Article> myArticles = articles.All;
Later I output the contents of the list in a JSON format (for CMS UI - table list).
Now a single record would include:
article.Title
article.Alias
article.Guid
article.Description
+
article.SeoProperties.TitleOverride
article.SeoProperties.H1Tag
article.StateProperties.IsActive
article.StateProperties.Channels
etc...
as you can see an Article object has an additional class property - with common properties (used on other object types in the CMS)
I also use a filter class that does some filter operations with LINQ on the collection to return me only articles within a certain channel, for example...
So the problem is that when I serialize the collection as JSON - there are only a few "columns" that I really need to display in my table list, while I have no need in other fields - especially, possibly long fields such as "description" (lazy loaded from file system), etc... - I serialize with DataContractJsonSerializer...
I need a way to control what fields will be included in the JSON result... What I do is I use reflection to set property values to null if I don't need the property and
decorate class properties with [DataMember(IsRequired = false, EmitDefaultValue = false)] attributes... - it should work well - but - as soon as I go over (even cloned!!) collection of final objects to strip off the fields = set value to "null" - property value becomes null - application wide - in all collections of such objects... eh ?
Some demo code in here:
void Page_Load() {
MyCms.Content.Games games = new MyCms.Content.Games();
List<MyCms.Content.Games.Game> allGames = games.All;
MyCms.Content.Games games2 = new MyCms.Content.Games();
List<MyCms.Content.Games.Game> allGamesOther = games2.All;
Response.Write("Total games: " + allGames.Count + "<br />");
//This is our fields stripper - with result assigned to a new list
List<MyCms.Content.Games.Game> completelyUnrelatedOtherIsolated_but_notSureList = RemoveUnusedFields(allGamesOther);
List<MyCms.Content.Games.Game> gamesFiltered = allGames.Where(g=>g.GamingProperties.Software=="89070ef9-e115-4907-9996-6421e6013993").ToList();
Response.Write("Filtered games: " + gamesFiltered.Count + "<br /><br />");
}
private List<MyCms.Content.Games.Game> RemoveUnusedFields(List<MyCms.Content.Games.Game> games)
{
List<MyCms.Content.Games.Game> result = new List<MyCms.Content.Games.Game>();
if (games != null && games.Count > 0)
{
//Retrieve a list of current object properties
List<string> myContentProperties = MyCms.Utils.GetContentProperties(games[0]);
MyCms.PropertyReflector pF = new MyCms.PropertyReflector();
foreach (MyCms.Content.Games.Game contentItem in games)
{
MyCms.Content.Games.Game myNewGame = (MyCms.Content.Games.Game)contentItem.Clone();
myNewGame.Images = "wtf!"; //just to be sure we do set this stuff not only null
pF.SetValue(myNewGame, "GamingProperties.Software", ""); //set one property to null for testing
result.Add(myNewGame);
}
}
return result;
}
Objects are set to their "Default values" (basically, null, in most cases) with this:
private object GetDefaultValue(Type type)
{
if (type.IsValueType)
{
try
{
return Activator.CreateInstance(type);
}
catch {
return null;
}
}
return null;
}
Quite probably your having trouble with differentiating between a shallow copy and a deep copy.
If a field is a value type, a bit-by-bit copy of the field is performed. If a field is a reference type, the reference is copied but the referred object is not; therefore, the original object and its clone refer to the same object.
With a deep copy when you clone an object and that object has a field of reference type, a new clone of that object is created and assigned to the field (vs just referencing the first object). Thus you have to completely different objects that share nothing.
That means if you're using clone and some of the properties are in fact subproperties (that is, properties of an instance inside the original object) you're changing it application wide, because you're acting upon a reference, not a new instance of the subobject.
You have more information about it in
http://msdn.microsoft.com/en-us/library/system.object.memberwiseclone.aspx
You could create a kind of modelview classes with the necessary fields and use something like Automapper to fill them. By this way, you will have a nice code, easy to maintain and highly customizable.

How do I copy an instance of an object?

I'm trying to write some code that populates a List (actually, it's a series of Lists, but we can pretend it's just one List). The idea is to add an IPackage to the List for the total quantity of IPackage on order. See the following code:
ParseExcel pe = new ParseExcel();
Pinnacle p = pe.ParsePinnacleExcel();
Rack r = new Rack(20,2,4.5,96,42,6,25*12);
foreach (PinnacleStock ps in p.StockList.Where(x =>
x.ColorCode == "10" &&
x.PackageLength == 30.64))
{
for (int i = 1; i <= ps.OnOrder; i++)
{
r.TryAddPackage((IPackage)ps);
}
}
Everything seems to be working well, insofar as the IPackage is repeatedly added to the list. However, it seems that the same instance of the object is being added, i.e. the object is not being copied each time it's added to the list.
What do I need to do to ensure that a copy of the object is inserted into the list, and not just an additional reference?
Then you need to implement ICloneable and replace
r.TryAddPackage((IPackage)ps);
with
r.TryAddPackage((IPackage)ps.Clone());
It's up to you to decide how Clone should populate the new instance of PinnacleStock that it returns.
At the most basic level, you could say
public PinnacleStock : ICloneable {
public PinnacleStock Clone() {
return (PinnacleStock)this.MemberwiseClone();
}
object ICloneable.Clone() {
return Clone();
}
// details
}
This will just do a shallow copy of PinnacleStock. Only you know if this is the correct semantics for your domain.
If you only need a shallow copy, then you can write a quick-fix clone method:
public class PinnacleStock : ICloneable
{
public PinnacleStock Clone()
{
return (PinnacleStock)this.MemberwiseClone();
}
object ICloneable.Clone()
{
return Clone();
}
// Other methods
}
If you need a deep copy (i.e. if PinnacleStock has sub-objects that you want to be copied as well), then you will need to write one yourself.
As others have said, you would need to make that copy, in some PinnacleStock-specific way:
foreach (PinnacleStock ps in p.StockList.Where(x => x.ColorCode == "10" &&
x.PackageLength == 30.64))
{
for (int i = 1; i <= ps.OnOrder; i++)
{
PinnacleStock clone = ps.CopySomehow(); // your problem
r.TryAddPackage((IPackage)clone);
}
}
However, you might want to question whether this is the right solution. Do you really need a separate instance of the PinnacleStock? Does adding a PinnacleStock to a Rack really create a new, independent instance? Are you planning to modify or track each of these individual copies separately? Is it correct that now you will have PinnacleStock instances that don't appear in your StockList? Not knowing your domain or the semantics of PinnacleStock, it's hard to be sure, but you might want to consider, say, creating a PinnacleStockRackEntry object to represent an instance of a PinnacleStock -- depends on the intended semantics of course!
You have to supply the logic to copy the object yourself. .Net does not have deep-copy built-in anywhere (with the notable potential exception of serialization). The closest it comes is the MemberwiseClone() method, but even that would copy references for any members of your type that are themselves reference type.

Categories