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.
Related
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.
I read about indexers in MSDN - Indexers which explains how we can use objects like array with index i.e. just like normal Array. However, I think we can create array of objects like
point[] array = new point[100];
So what is the special advantages Indexer over object array?
If all you are after is a collection of objects then an indexer has absolutely no benefit over an array. However, if you need to store state as well as a collection, that's where an indexer shines.
For example, consider the following
public class Tree
{
private Branch[] branches = new Branch[100];
...
public string Name { get; set; }
public Branch this[int i]
{
get
{
return branches[i];
}
}
}
Tree holds an internal collection but also has state of it's own. Having an indexer property allows for simple access to the underlying collection e.g.
tree.Name = "Tree";
var branch = tree[0];
Not in this case that you have mentioned above. However, if you have anything that cannot be represented as an array will be a good example for Indexers to be used.
One .Net framework example is Dictionary. If you see the definition of Dictionary type in .Net you will find that they let you get an access of value through key. So that is a good example of using indexers where the index is presented as string.
Without indexers, how would you do that? of course by index value but it cannot be of type string then, will that be user friendly? I guess not!
So indexers gives you an opportunity to represent your code well.
Similarly, in case of point type, of course you can access the value of by index i.e. 0,1,2...99. What if you want to make more user friendly, such as point["x"]. That is where Indexers will help you.
Another example I could think of how about if you want to access your stack like s1 instead of push and s[0] instead of pop method.
There is a very good example of indexers by Microsoft where you can access file byte by byte by providing character location as index.
http://msdn.microsoft.com/en-us/library/aa288465(v=vs.71).aspx
In your line of code, you've defined an array of point objects, whatever those might be.
point[] array = new point[100];
Assuming you have direct access to the array, you can access the first element in your array like this:
var firstPoint = array[0];
The page you linked to is showing you how you could access that array, if it were defined inside your class, and you didn't have direct access to the array (since it's private).
For example, we could modify the example on that page to use your array:
class SampleCollection
{
private Point[] arr = new Point[100];
public Point this[int i]
{
get { return arr[i]; }
set { arr[i] = value; }
}
}
Then you could access the first element in the array like this:
var sc = new SampleCollection();
var item1 = sc[0];
That isn't an indexer.
An indexer is not used to create an array of objects, it is actually an operator overload to the '[]' operator.
An example for it's use would be if you wanted to make a List wrapper class.
In order to preserve the square braces functionality you would need (and want) to override the square braces operator. This is done via an indexer method.
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.
Is it possible to know the length of a string array - without having an object instance - via reflection?
E.g. in this case: 2.
public string[] Key
{
get { return new string[] { Name, Type }; }
}
EDIT: ok, I will not try to do this, it doesn't make much sense.
Perhaps you mean "without having the exact type of the Array". C# Arrays all derive from Array, so you can cast an Array reference to Array and use the Length property.
If you TRULY wants to reflect the property,
var type = typeof(MyClass);
var prop = type.GetProperty("Key");
var method = prop.GetGetMethod();
var body = method.GetMethodBody();
var ils = body.GetILAsByteArray();
from here you'll have to use one of the various libraries to decode bytes to IL OpCodes (for example https://gist.github.com/104001) . The OpCode you are looking for is newarr. The last push of an int32 before the newarr is the size of the array.
You have two things going on there... telling the length of an array is pretty simple once you have an array; you just call .Length (in the case of a vector).
However, you mention an instance, and you are showing an instance property; which makes me think it is the containing object you lack. In which case... no. You can't make a virtcall on a null instance. And trying to use static-call on an instance member of a class is very evil; IIRC the runtime will kick you for this.
You could, however, make it a static property just by adding the static modifier. Then you just pass in null as the instance to reflection.
I guess you mean you want to know the size of the array the property will return if it were called?
I don't think you can do it sensibly.
If the property had a conditional then it could return different sized arrays, so
you'd have to evaluate the property to know the size. Which could have side effects or be dependent on other values in the object (or statics).
Consider this one:-
static public int n;
public string[] Key
{
get {
if (n > 1)
return new string[] { "Name", "Type" };
else
return new string[] { "Name", "Type", "Cheese" };
}
}
Basically, you'd have to run the code.
Good morning,
Suppose I have a class
public class Class
{
int something;
int[] otherThing;
}
and I want to make objects of type Class immutable. Suppose also that I have a very frequent operation which creates a new object of type Class,
public Class SomeFunction()
{
int[] Temp = new int[] { ... };
return new Class(1, Temp);
}
To avoid creating new objects too often, and since Tempis no longer accessible out of the method, is it too bad to set on the constructor
this.otherThing = Temp;
instead of
otherThing = new uint[Temp.Length];
for (int i = 0; i < Temp.Length; i++)
{
this.otherThing[i] = Temp[i];
}
?
Thank you very much.
If the constructor that does this is private its fine IMO. Since you know the content of the other array will never change you can directly use it. You could even share one instance of the array between several instances of your class if you want to without causing any problems.
A public constructor directly using a provided array is a bad idea on the other hand. Since that can be used to break immutability.
It is better to assign a copy of temp to otherThing so that any changes to otherThing will not change temp. You can also use the Array.CopyTo method for this purpose.
In addition you should seriously consider using IEnumerable<int> or IList<int> instead of int[] because arrays by nature work against the idea of immutability. Read this blog post by Eric Lippert.
The difference is that in the first option you always get a new instance and in the second one all the created "Class"es will point to the same array (!). So if you change something in the array in any Class, all the other classes are changed.