C# List Objects - c#

I have a list of Character objects I made and a list of Cells which can contain one character. Is it possible for my Character object to be added to the list and be assigned to a cell and changes I make to it in the party list or the cell to effect the object in both place? I don't really know how the pointers will work out for this. I figure what will happen is the object in the list is a separate object from the one assigned to the cell.
Sorry my code is very large so I don't want to post it all here but the Character I am talking about is a custom class I made. I suppose my question really boles down to two questions. When I put something in a list is that changing where the pointer points or is that a new object all together. Also can I have multiple pointer if I add something to a list then assign that to another instance of the character object will referencing the Character from the Cell Object be the Same as referencing my Character from the other list object.

As long as your Character is a class (i.e. a reference type) then you are essentially storing references to Character objects. Any changes you make to an object through a reference to it will be visible when the object is accessed through any other reference.
Example:
class Character
{
public string Name { get; set; }
}
var c = new Character();
var c2 = c;
var arr1 = new Character[] { c };
var arr2 = new Character[] { c };
arr1[0].Name = "Foo";
Console.WriteLine(arr2[0].Name); // "Foo"
Console.WriteLine(c2.Name); // also "Foo"

So basically you want to treat Characters as a reference type.
Just create your own wrapper object which contains a character inside it.
public MyCharacter
{
public char character{get;set;}
}
Objects are treated by reference, so that should work for you.

Related

Lists getting cleared unexpectedly after assignment [duplicate]

This question already has answers here:
How do I clone a generic list in C#?
(29 answers)
C# Value and Reference types
(6 answers)
Closed 4 years ago.
class ListHolder
{
public List<char> List;
public ListHolder(List<char> l)
{
this.List = l;
}
}
class Program
{
static void Main(string[] args)
{
List<char> a = new List<char>();
a.Add('s');
ListHolder c = new ListHolder(a);
a.Clear();
Console.WriteLine(c.List.Count);
}
}
I've put some list into that class, than I cleared the list and wrote the count of the list in the class... I would expect that the output should be "1" (as the list in the class contains the letter 's') but instead it writes "0". How is possible, that a.Clear clears even the list in the class? How can I achieve clearing only the list in the Main and the list in the class letting be?
Since you are passing a reference instead of the list itself, you will get 0 after clearing your list.
What you have to do is passing to the class a new List containing the other list's values:
cl c = new cl(new List<char>(a));
This way, even if you clear the 'main' list, in your class you'll have 1 as items count.
Hope this helps.
List and other classes are reference types. In few words, it means you have an object somewhere in memory and a reference(s) on it.
this.l = l; means you copied the reference to the first list to the class field. So you have one list and two references on it. And when you clear the list via a variable, no matter how you address it after clearing - via a or cl.l. Your single list is cleared already.
If you want to avoid this, you need to create a copy of list in your constructor:
public cl(List<char> l)
{
this.l = new List<char>();
this.l.AddRange(l);
}
}
I recommend you to read more information about reference types. They are used widely and knowledge about them will give you a good base for programming skills.
if (a is System.ValueType)
{
//never
Console.WriteLine("List is value type");
}
if ('s' is System.ValueType)
{
//always
Console.WriteLine("char is value type");
}
I think you know, char is value type, but list is reference type.
Even code like this; it would be same.
List<char> a = new List<char>();
a.Add('s');
List<char> c = a;
a.Clear();
Console.WriteLine(c.Count);

Solution to avoid deep copying in C#

I have a variable var1 which is a customized class that contains a single list of strings. I have another variable var2 which is a list of classes like var1.
What I am aiming to do is I need to iterate over var2, class by class and instantiate AddRange to combine var1s list of string with var2's ith class's own list of string. This is done independently, meaning that var1's list of strings stays the same at each iteration. Only at each iteration will its list of string be combined with that of var2's list of string, but after this iteration, it must revert back to the original. The problem is that I cant get this to work. Each time i add an string, it doesn't revert back.
I've tried making a deep copy and at the end of each iteration setting the intermediate clone class to null. Any ideas?
Below is a rough "PeudoCode"
public void combineString(CustomClass var1)
{
// var2 is a class variable that contains a list of CustomClass
List<CustomClass> finalized = new List<CustomClass>();
for (int i = 0; i < var2.Count; i++)
{
CustomClass tmpVar = (CustomClass)var1.Clone();
tmpVar.addString(var2[i].StringSet); //each Custom class has a stringSet which is a list of strings
// .....Do some analysis of the strings of tmpVar
// if it passes the analysis add tmpVar in to finalize list
// none of the other components should change
if (pass analysis)
{
finalized.Add(tmpVar);
}
tmpVar = null;
}
// When the loop is done, the 'finalized' variable is a list of
// CustomClass but then each element inside finalized contains the same string set.
Console.WriteLine("Done");
}
So, var1 must be unchanged. Either combine the strings into the other var1, or if that one must too be left as is, use a new list all together. I see no need to bother with cloning.
So, you basically have to concatenate two lists of strings in a single string without touching the strings themselves.
Would something like this do for you?
string concatenated = var1.Concat(var2[i].StringSet).Aggregate((item1, item2) => item1 + item2);
Aggregate iterates over an IEnumerable and returns the concatenation of all its items.

Why do I need to Instantiate an Object Array Twice?

I have created an Object array like this. But to assign value to object, I have to instantiate each object at every positions of the array? Why do I need this?
This is My method
StageObject[] StageSplitDate = new StageObject[Stages.Rows.Count];
for (int i = 0; i < Stages.Rows.Count; i++)
{
StageSplitDate[i] = new StageObject();
StageSplitDate[i].StageId = "String Value";
StageSplitDate[i].FromTime = StartTime;
StartTime =StartTime.AddMinutes(Convert.ToDouble(10));
StageSplitDate[i].ToTime = StartTime;
}
return StageSplitDate;
And Object Class
public class StageObject
{
public string StageId { get; set; }
public DateTime FromTime { get; set; }
public DateTime ToTime { get; set; }
}
I have to instantiate each object at every positions of the array?
You are not instantiating the array elements twice. In the first line you instantiated an array StageSplitDate with every element set to null.By default each array (of reference types) element is initialized to null. To use it further you need to instantiate each object in the array as well, otherwise you will get null reference exception.
For C#
Arrays (C# Programming Guide) - MSDN
The default value of numeric array elements are set to zero, and reference elements are set to null.
(Since the question was originally tagged for java)
For JAVA
4.12.5. Initial Values of Variables
Each class variable, instance variable, or array component is initialized with a default value when it is created (§15.9, §15.10):
For all reference types (§4.3), the default value is null.
Your array is an array of StageObject references. The StageObjects themselves don't exist yet. Essentially each entry in the array merely "points" to or "refers" to a StageObject.
Before you call new StageObject(), each array element is null, meaning it's referring to nothing.
Think of an analogy where an array is a bookshelf. If you want a shelf of books, just buying the shelf is only the first step; you then need to buy each book and put it on the shelf. Same idea here: allocating the array gives you an empty container, and then you need to create each object and put it into the container.
Why is it like this? Because an initially-empty array is often what you want -- and even if it isn't, unless your object only has a no-arg constructor, Java wouldn't even know how to construct each object.
new StageObject[Stages.Rows.Count] creates a new array of StageObject references containing Stages.Rows.Count null references. You want each element to point to a StageObject. To do that, you need to create some StageObject instances.
StageObject[] StageSplitDate = new StageObject[Stages.Rows.Count];
The above statement only makes reference array for StageObject which are intialized with null but does not actually initanstiate the objects of StageObject
StageSplitDate[i] = new StageObject();
The above statement is creating object of type StageObject and assigns the reference to StageSplitDate element

How to get a list of mutable strings?

I have the following piece of code
List<String> l = new List<String>();
String s = "hello";
l.Add(s);
s = "world";
When I set up some breakpoints and go through the program, after executing the last line, the value in the list is still hello instead of world.
Shouldn't it equal world ? Isn't a string an object, and am I not just inserting a pointer into the list? Later on if I change the string to point to a different value ("world"), why is my list still referencing the old value?
How can I get my desired effect ?
Thanks a lot!
Strings are immutable so that won't work. When you attempt to set into it, you actually drop the pointer to the old string and create a new one under the hood.
To get the desired effect, create a class that wraps a string:
public class SortOfMutableString
{
public string Value {get;set;}
public SortOfMutableString(string s)
{
Value = s;
}
public static implicit operator string(SortOfMutableString s)
{
return s.Value;
}
public static implicit operator SortOfMutableString(string s)
{
return new SortOfMutableString(s);
}
}
And use this in your list. Then references will point to the class, but you can contain the string value inside. To make it even better, override implicit casting to and from string so you don't even need to see that you are talking to a SortOfMutableString.
Refer to Jon Skeet's answer for undoubtedly a very accurate explanation about string's in C#, I'm not even going to bother!
Alternative class names:
PseudoMutableString
ICantBelieveItsNotMutable
HappyAndReferenceableString
You're changing the s reference to refer to a different String instance.
Strings are immutable; it is impossible to change the existing instance that you added to the list.
Instead, you can create a mutable StringHolder class with a writable String property.
No, it shouldn't equal world. The value of the variable s is a reference. When you call l.Add(s), that reference is passed by value to the list. So the list now contains a reference to the string "hello".
You now change the value of s to a reference to the string "world". That doesn't change the list at all.
It's important to distinguish between three very different concepts:
A variable (which has a name and a value)
A reference (a value which allows you to navigate to an object, or null)
An object
So in particular, the list doesn't know anything about the variable s - it knows about the value which was passed into Add; that value happened to be the value of s at the time Add was called, that's all.
You may find these articles helpful:
Values and references
Parameter passing in C#
No, there are two different references involved. One called s and one that's at List[0]. When you say l.Add(s) you are setting the list reference to the same address as s, but then when you assign s to "world", then s will point to the new string, leaving List[0] pointing to the old string.
If you really want to do something like what you are asking, you'd need to wrap the string in another object that contains a string, so that s and List[0] both refer to that object, and then that object's reference to a string can change and both will see it.
public class StringWrapper
{
public string TheString { get; set; }
}
Then you can do:
var s = new StringWrapper { TheString = "Hello" };
var l = new List<StringWrapper>();
l.Add(s);
s.TheString = "World";
And now l[0].TheString will be world too. This works because in this case we are not changing the reference in List[0] or s, but they contents of the object referred to by s and List[0].
A variable is an object reference, not an object itself. s = "world" says "make s refer to the string "World") - it does not in any way affect the string "hello" that s was previously referring to. Furthermore, strings in C# are always immutable. You can, however, make the first list element (which currently refers to "hello") refer to a different string: l[0] = "world".
The other two answers here did a great job of saying why what you tried didnt' work, but you were looking for a solution for your desired effect. Wrap a string (property) inside of an object. Then you can change that string and it will be reflected in the collection.

Store a reference to a string

I have a class that has 3 string properties. I want to store these in a list so that when I make changes to the strings of the list they also get updated in the class.
This would be easy to do if I was using class object, but string seems to behave differently. It seems to make a copy of the object for the list rather then have a pointer to the object. How am I supposed to do this is C#? If this is not possible is there a better way?
The problem with strings is that they are immutable. In other words, you can never change a string once it is created.
Thus, if you want to 'change' a string, you must remove the original from the List, and store the result back into the list. Example:
string a = "abcdefg";
List<String> list = new List<String>();
list.add(a);
a = a.Substring(0, 5);
That code does nothing because the string a is pointing to never changes. It just points to a new string.
In .NET, strings are immutable. If you change the string, you are in fact creating a new one and modifying the reference.
I would consider using a StringBuilder object to address your problem.
Strings are immutable. You can change a reference to point to another string but you cannot modify a string such that other references to it change value as well (except by unsafe, completely dangerous reflective code)
What you want to do is deal with this either through using a mutable alternative, (such as a StringBuilder) or via explicit indirection. I'll show you the latter:
public class Props
{
private readonly string[] data = new string[2];
public string Foo {
get { return data[0]; }
}
public string Bar {
get { return data[1]; }
}
public IList<string> ModifyValueButNoInsertsList { get { return data;} }
}
Really you should consider actually using string[] rather than IList in this situation as it makes it clear inserts are forbidden, only alterations of the values. Since string[] implements IList<string> this is unlikely to be a problem
Since strings are immutable, the simplest work-around is to instead store the reference to a string array with one element. Replacing that element will then be noticed by anyone with a reference to the array.
Strings in C# are immutable, so you cannot change a string in C# - you can only create new strings.
You could rather store a class that has a string member
class StringHolder {
public StringHolder(string s) { str = s;}
public string str;
}
...
List<StringHolder> l1 = new List<StringHolder>();
List<StringHolder> l2 = new List<StringHolder>();
List<StringHolder> l3 = new List<StringHolder>();
StringHolder h = new StringHolder("Test\n");
l1.add(h);
l2.add(h);
l3.add(h);
h.str = h.str.Replace("\n","");
Now all lists refer to the same StringHolder and will naturally see the same string.
Another option is to store StringBuilder objects in your lists instead of a String.
class StringHolder
{
public string Value { get; set; }
}
Keep a list of those instead of just strings. Then you can get/set the Value property to update the string value.
You're looking for a mutable string of some kind. There are a lot of ways to create a class that behaves the way you want it.
The easiest way would be to use a StringBuilder object instead of a string. You just have to be careful to not make new StringBuilder objects, but rather alter the existing one. Depending on what you need, this may not be the best option.
Alternatively you can create your own wrapper class for String that you can manipulate freely. The downside is you may have to write a lot of stub methods that call down to the inner string depending on how you want to use it. It would be easier to just expose a read/write string property. This has the advantage of letting you define exactly what behaviours you want, but will take longer to write in the first place. Again, you'll have to make sure to not create new instances of the wrapper class, but rather just alter the class's internal string.
Wrap your string into a custom class, this will allow you to share it amongst a number of different locations. You could also choose to store Char arrays instead.
As a side note (like several have mentioned), if you're doing some heavy processing with strings, use the StringBuilder class. Because of the immutable nature of strings, changing/concatenation of them in loops or what have you - will cause a lot of overhead.
StringBuilder is your friend.

Categories