How to unchain items in list<t> class - c#

can some one explain to me how to break the chain with a NEW statement?
Let me clarify the chain I’m talking about. When I call to a class I use the NEW statement like so
Myclass x =new Myclass();
My understanding is this creates a new empty instance of Myclass. Now correct me if I’m wrong but having a new empty instance one should be able to add what ever data the class supports?
I use this lot and would think the above to be true until adding data in such a manner
Myclass x =new Myclass();
//oldMyclass being old data that needs to be changed then
//added back to the class as a new or duplicate entry
x = oldMyclass[1];
//we change the data
x.red= 0x54;
//we add it back
oldMyclass.add(x);
All is good until we edit the data after adding it say we need to change another value.
We access the oldMyclass and select the proper item say its index is 2 but we only want to change the values of index 2
Myclass x =new Myclass();
x = oldMyclass[2];
x.red=soemvalue;
oldMyclass[2] = x;
This will change the red value of both index 1 and index 2. How can I break the chain between index 1 and index 2?
I think I might have over simplified this question let me know.
Thanks for any information.
Edit: Here is the copy method that I tried
public static Items.SavedItem Copy(Items.SavedItem old)
{
Items.SavedItem x = new Items.SavedItem();
x.generator = old.generator;
x.hireling_class = old.hireling_class;
x.id = old.id;
x.item_slot = old.item_slot;
x.owner_entity_id = old.owner_entity_id;
x.socket_id = old.socket_id;
x.square_index = old.square_index;
x.used_socket_count = old.used_socket_count;
return x;
}

So let's say, for arguments sake, you have a class like this:
public MyClass
{
public string Foo { get; set; }
}
And you have a collection
List<MyClass> myList = new List<MyClass>();
Now you create an instance of MyClass
MyClass obj1 = new MyClass() { Foo = "bar" };
Now if you do this:
myList.Add(obj1);
myList.Add(obj1);
You now have a list with TWO members, but they happen to be the same object. Whats stored in the list is a reference to the object you added, not the object itself. So myList[0] == myList[1]
Now if you did this:
MyClass item = myList[1];
And then:
item.Foo = "something else";
Both the item at index 1 and the item at index 0 will have 'Foo == "something else"' because they are the same item.
Another point that seems to be confusing you is this: myList has two items. If I do this:
MyClass item = myList[0];
myList still has two items. Indexing a collection doesn't remove it and because of that, there is no need to add the item back to the list. It's already there. All I've done is copy the reference from myList to a variable named item.
There are collections (Stack and Queue for example) that do work on the principle that you will remove items and (potentially) add them back, but List doesn't work that way.
So if you wanted to add multiple objects to myList you need to create multiple objects with the new keyword. For example:
List<MyClass> myList = new List<MyClass>();
MyClass obj1 = new MyClass() { Foo = "bar" };
myList.Add(obj1);
obj1 = new MyClass() { Foo = "something else" }; // Note: I've reused the variable, but this is a *new* object
myList.Add(obj1);
Or, if you don't need the new object assigned to a variable, you can simply if to:
List<MyClass> myList = new List<MyClass>();
myList.Add(new MyClass() { Foo = "a" });
myList.Add(new MyClass() { Foo = "b" });
Or even more compactly, you can exploit the collection initialization syntax and simply:
List<MyClass> myList = new List<MyClass>()
{
new MyClass() { Foo = "a" },
new MyClass() { Foo = "b" }
}
If you want to copy an object from your list, then you need to copy each property (and if it contains other objects, you may need to copy them too). There are various ways to do this, IClonable or a copy constructor are examples, but it basically comes down to, at some point, doing something like this:
myCopy.Foo = myOriginal.Foo;
myCopy.Bar = myOriginal.Bar;
// repeat for all properties that you want to copy.
Now assuming that Foo and Bar aren't also reference types, you have a copy. If they are reference types, you have a copy, but myCopy.Foo and myOriginal.Foo are still pointing at the same object.

Related

Predefine field in class using several commands

Let's say I have this class with a constructor that fills the internal list with two entries:
class MyClass
{
IList<int> someList;
public MyClass()
{
someList = new List<int>();
someList.Add(2);
someList.Add(4);
... // do some other stuff
}
}
Now let's say I have several constructors which all do the same with the internal list (but differ in other aspects).
I would like to know if I can outsource the generation and filling of the list directly to the field, like this:
class MyClass
{
IList<int> someList = new List<int>(); someList.Add(2); someList.Add(4);
// Does not compile.
public MyClass()
{
... // do some other stuff
}
}
Is it possible to call several commands in the field definition, and if yes, how?
You can pre-instantiated IList like this and add your values per accessing the Indexer:
IList<int> someList = new List<int>() { 2, 4 };
This will be initialization happens before the constructor is used.
Update 1
As OP mentioned in the comments, for LinkedList<T>() you have to use the constructor with some IEnumarable (in my Example an Array).
LinkedList<int> myList1 = new LinkedList<int>(new int[] {2,3,4});
Update 2
After reading your last comment, you're looking for Fluent Interfaces in your instantiation process. This is a method of chaining functions together and would look something like this:
Customer c1 = new Customer()
.FirstName("matt")
.LastName("lastname")
.Sex("male")
.Address("austria");
This functionality is not given by default in Collection Classes.You have to implement your own version of IList<T> for this.
Lambda Expression is a way to achieve this, like your update shows...
Got it:
IList<int> someList = new Func<List<int>>(() => { IList<int> l = new List<int>(); l.Add(2); l.Add(4); return l; })();
Explanation:
() => { IList<int> l = new List<int>(); l.Add(2); l.Add(4); return l; }
is a function taking no argument and returning an IList<int>, so it is a Func<IList<int>>.
Althoug the compiler knows this, it seems I explicitly have to state that fact via
new Func<IList<int>>(...)
to be able to call it later. The call is done as usual by putting two brackets () behind the Func.
Or to write it in a more readable way (then I don't even need the new keyword, but instead must make the Func static):
static Func<IList<int>> foo = () => { IList<int> l = new List<int>(); l.Add(2); l.Add(4); return l; };
IList<int> someList = foo();

Generating a new instance of a List in C#

I have a problem with using C#, if I initialize a certain list, lets say List<T> exampleList using another pre-existing list, lets say toModify like this: List<T> exampleList = new List<T>(toModify). When I later modify toModify list the newly created list also modifies itself. If it passes the value by reference shouldn't the value of exampleList stay the same since it was generated from the other one?
TLDR: Value of a list I initialize using another list(second list) changes when I change the second list. I come from a Java background and can't understand why this happens. Will I always have to use clone?
Let us use this example :
List<A> firstList = new List<A>()
{
new A() { Id = 3 },
new A() { Id = 5 }
};
List<A> secondList = new List<A>(firstList);
secondList[1].Id = 999;
Console.WriteLine(firstList[1].Id);
Output : 999
The main reason for this is that even though we created a new List<T> that points to a new memory allocated on heap it still works with references the point to same objects.
To create a list that points to new (!) objects with the same values we'd need to clone these elements somehow, one way to do it is to use LINQ .Select() method in order to create new objects and then a ToList() method to copy the list itself:
List<A> firstList = new List<A>()
{
new A() { Id = 3 },
new A() { Id = 5 }
};
List<A> secondList = firstList.Select(el => new A() { Id = el.Id }).ToList();
secondList[1].Id = 999;
Console.WriteLine(firstList[1].Id);
Output : 5
Yes.
You're creating a new list containing the same items as the old list. If you clear the first list, the items in the second stay.
But if you change a property for one of the items in the first list, then it is the same object in the second list.
So, both list are referencing the same items in memory. When you write list1[0].SomeProperty = 1 you're changing that using object reference that is the same in list2, so changes are reflected in the second list.
For how to clone a List and generate new references for items, check this SO Answer.
In the following line:
List<T> exampleList = new List<T>(toModify)
you create a list of T calling List<T>'s constructor that takes one argument of type IEnumerable<T>. For further info on the latter, please have a look here.
Method's arguments in C# are passed by default by value and not by reference. They can be passed by reference, but you have to explicitly state this in the signature of the corresponding method using the ref keyword and at the point you call this method, using again the same keyword. So the toModify is passed by value to the constructor of List<T>.
What's the importance of this?
In C# types can be divided into two categories (despite the fact that all types inherit from the System.Object):
Value types
Reference types
When we pass a value type as an argument, we pass a copy of it's value. Each modification we make in either the original value or in the copy of the original value is not reflected to one another. On the other hand, when we pass a reference type as an argument, we pass a copy of that reference. So now we have two references (pointers) that point to the same location in memory. That being said, it's clear that if we change any property of the object in which both references points to, this would be visible by both of them.
In your case, this is what is happening. toModify is a list of reference types (under the hood you have an array, whose items are references to other objects). So any change to the items of the initial list, toModify, is reflected to the list you construct based on this list.
A simple example that you could use to verify the above is the following:
public class Point
{
public int X { get; set; }
public int Y { get; set; }
public override string ToString() => $"X: {X}, Y: {Y}";
}
class Program
{
static void Main(string[] args)
{
var listA = new List<int> {1, 2, 3};
var listB = new List<int>(listA);
// Before the modification
Console.WriteLine(listA[0]); // prints 1
Console.WriteLine(listB[0]); // prints 1
listA[0] = 2;
// After the mofication
Console.WriteLine(listA[0]); // prints 2
Console.WriteLine(listB[0]); // prints 1
Console.ReadKey();
var pointsA = new List<Point>
{
new Point {X = 3, Y = 4},
new Point {X = 4, Y = 5},
new Point {X = 6, Y = 8},
};
var pointsB = new List<Point>(pointsA);
// Before the modification
Console.WriteLine(pointsA[0]); // prints X: 3, Y: 4
Console.WriteLine(pointsB[0]); // prints X: 3, Y: 4
pointsA[0].X = 4;
pointsA[0].Y = 3;
// After the modification
Console.WriteLine(pointsA[0]); // prints X: 4, Y: 3
Console.WriteLine(pointsB[0]); // prints X: 4, Y: 3
Console.ReadKey();
}
}

Deep copy of a list with class elements

EDIT:
To whoever marked the question as duplicate. That question is for how to create a deep copy. My question was how to make sure a the copy constructor is called when copying a list of class elements.
I'm trying to make a deep copy of a List that contain custom class elements. If I have a List of strings I can just use
List<string> secondList = new List<string>(firstList);
and then freely modify the elements in the second list without effeting the ones in the firwst list. But when I try to do the same with a custom class type both lists get changed. To try and solve it I made a small test program that just has this class.
class TestClass
{
public string name;
public TestClass(string n)
{
name = n;
}
public TestClass(TestClass original)
{
name = original.name;
}
}
And all my program does is this
TestClass t = new TestClass("Name1");
List<TestClass> list1 = new List<TestClass>();
list1.Add(t);
List<TestClass> list2 = new List<TestClass>(list1);
list2[0].name = "Name2";
That last line of code changes the name of the first element in both lists, which I do no want.
The issue here is that your objects are reference types, and the lists hold references to those objects.
This means that even though your second list has a COPY of the references from the first list, the references are still pointing to the original objects.
In order to solve this, you must clone not the references in the lists but instead the actual objects that you have stored in the lists.
You have already defined a copy constructor for your class, so you can use that to make a deep copy of the list as follows:
var list2 = list1.Select(item => new TestClass(item)).ToList();
You create a reference with this line of Code:
List<TestClass> list2 = new List<TestClass>(list1);
But you won't like to use Call-by-Reference. You Need Call-by-Value
in this Approach.
so the working code in lambda-expression is the following one:
TestClass t = new TestClass("Name1");
List<TestClass> list1 = new List<TestClass>();
list1.Add(t);
List<TestClass> list2 = new List<TestClass>();
list2 = list1.Select(item => new TestClass(item)).ToList();
list2[0].name = "Name2";
Have fun with it...

C# Object properties changes when clearing Wpf controls

I have a class which have a list
public static List<bar> tempList = new List<bar>();
public static Foo foo = new Foo();
public class bar(){
public string name;
public int age;
}
public class Foo(){
public List<bar> lBar = new List<bar>();
}
I have several textbox controls: age1, age2
on textChange on each control a create a new object
/*------------------------------------------------------------------
Following code: I want runtime calculation for a logic i did with age.
also need to create a new object using the inputs
------------------------------------------------------------------*/
age1_textChaned(...){
createObj( );
}
age2_textChaned(...){
createObj( );
}
private void createObj(){
if(tempList.Count != 0)
tempList.Clear();
if(age1.Text != "")
tempList.Add(new bar("name1", Convert.ToInt32(age1.text));
if (age2.Text != "")
tempList.Add(new bar("name2", Convert.ToInt32(age2.text));
}
Then i have a button btn1 which will create the object then clear the content of textbox.
btn1_Click(...){
foo.lBar = tempList;
clearFields(); //here lies the question, once i clear the fields,
//somehow it is still affecting the values in foo.lBar;
}
private void clearFields(){
age1.Text = "";
age2.Text = "";
}
so when i do this
btn2_Click(...){
foreach(bar b in foo.lBar){ //foo.lBar is empty i dont know why
...
}
}
my current solution on btn1_click i have this
foreach(bar b in tempList)
foo.lBar.Add(b); // instead of foo.lBar = tempList
is the foo.lBar = templist causing these changes?
snippet is only a simpler version of an entirely different project.
Objects in C# are passed around by reference unless specified otherwise.
For example, here is the code you are running and how it works behind the scenes :
// create a new location in memory and refer to it using the variable tempList
public static List<bar> tempList = new List<bar>();
// add a new item to the list
tempList.Add(new bar("name1", Convert.ToInt32(age1.text));
// make the variable foo.lBar to also refer to the same spot in memory as tempList
foo.lBar = tempList;
// clear the spot in memory containing the list
tempList.Clear();
That last line affects both the tempList variable and the foo.lBar variable because they both refer to the same location in memory.
The solution to avoid this is to create a new copy of an object in memory so the two variables are pointing to two separate instances in memory, and clearing one does not clear the other.
That is why your current solution works
// add the memory location of each item in tempList to foo.lBar's list
foreach(bar b in tempList)
foo.lBar.Add(b);
Note that if you call tempList.Clear() it will only clear the memory references being stored in tempList, however the actual objects will still exist in memory elsewhere.
Also with this solution if you did something like this :
tempList[0].name = "A changed name";
it would change the name property of the item in the foo.lBar list as well, since they both share the same reference in memory.

Finding the "mode" of pairs of numbers

My relevant code looks something like this:
//The object
Class MyClass
{
int PositionCount { get; set;}
Value { get; set;}
MyClass(int positionCount, double value)
{
PositionCount = positionCount;
Value = value;
}
}
//And then, later, using the object
List<MyClass> list = new List<MyClass>();
MyClass obj1 = new MyClass(18, 356.2);
list.Add(obj1);
MyClass obj2 = new MyClass(18, 356.2);
list.Add(obj2);
MyClass obj3 = new MyClass(19, 22.5);
list.Add(obj3);
MyClass obj4 = new MyClass(19, 30.325);
list.Add(obj4);
MyClass obj5 = new MyClass(19, 356.2);
list.Add(obj5);
What I'd like to find is the most common occurrence of number pairs in this list. Here, I'd expect to get back the values in obj1 and obj2, since they repeat two numbers each. I haven't had much luck with getting the modes of PositionCount and Value separately, as (in this case), the mode of PositionCount is 19 and Value is 356.2, but there is no pair (or more) of elements in the list with both of these numbers.
Thanks for any guidance.
Something like this:
var mostCommon = list
.GroupBy(x=>new {x.PositionCount, x.Value})
.OrderByDescending(x=>x.Count()).First();
It will group by your properties and then get that with biggest count

Categories

Resources