When and best way to make exact copies of strings in C# - c#

Let's say I have an array of strings from executing this Split method
string[] parsed = message.Split(' ');
And then I want to store a certain value of this array in a new string
string name = parsed[3];
Now I remove this string from the array using an extension method, this method removes the value at the specified index and shifts everything back to fill the gap
parsed = parsed.RemoveAt(3);
I am aware that because strings are reference types in C# my name variable is now null, after searching a little I've been told that making exact copies of strings in C# is useless. What is the best and correct way to set the name variable as a new instance so that it does not get deleted after the .RemoveAt() call?
EDIT:
This is the best way that I found so far
string name = new string(parsed[3].ToCharArray());
Another way proposed by Willy David Jr
parsed = parsed.Where((source, index) => index != 3).ToArray();
EDIT 2:
Please disregard this question and read the approved answer, I misunderstood how reference types work.

You're misunderstanding how reference types work. Removing an object from an array does not modify that object in any way - it just means that the array no longer contains a reference to the object.
You can test this yourself. Run the code you included in the debugger (or a console app) and then view (or print out) the value of name at the end.
The thing that can trick you up with reference types occurs when there are two variables (or arrays or whatever) that hold a reference to the same object. In this case, changes made to the object via one variable will be reflected when the object is accessed via another variable - it's the same object, but with two different variables referencing it. If you want both variables to refer to their own "copy" of the object, you have to create a copy yourself and assign it to one of the variables.
However, in C#, the string type is immutable, meaning that once a string object is created there is no way to change that object. So there is never a reason to create a copy of a string. If there is a variable that references a particular string, you can be sure that no other reference can change it out from under you.

Why do you think your name variable should be null? It will stay untouched after removal from array. Your original code is enough to accomplish what you desire.

Are you sure that there is RemoveAt at your string? There is RemoveAt on Collections but not on string or string array per se.
You can do this instead:
List<string> lstParse = new List<string>();
foreach (var i in parsed)
{
lstParse.Add(i);
}
string name = parsed[3];
lstParse.RemoveAt(3);
To join again the list and convert it to string:
string strResult = string.Join(" ", lstParse.ToArray());
If you really want to remove index without a new list of object, disregard the code above and you can do this one line instead:
parsed = parsed.Where((source, index) => index != 3).ToArray();

Related

String character array

Isn't a string already a character array in c#? Why is there a explicit ToCharacterArray function? I stumbled upon this when I was looking upon ways to reverse a string and saw a few answers converting the string to a character array first before proceeding with the loop to reverse the string. I am a beginner in coding.
Sorry if this seems stupid, but I didn't get the answer by googling.
Isn't a string already a character array in c# ?
The underlying implementation is, yes.
But you are not allowed to directly access that. String is using encapsulation to be an immutable object.
The actual array is private and hidden from view. You can use an indexer (property) to read characters but you cannot change them. The indexer is read only.
So yes, you do need ToCharacterArray() for reversing and similar actions. Note that you always end up with a different string, you cannot alter the original.
Isn't a string already a character array in c# ?
No, a string is a CLASS that encapsulates a "sequential collection of characters" (see Docs). Notice it doesn't explicitly say an "Array of Char". Now, it may be true that the string class currently uses a character array to accomplish this, but that doesn't mean it ~must~ use a character array to achieve that end. This is a fundamental concept of Object Oriented Programming that combines information hiding and the idea of a "black box" that does something. It doesn't matter how the black box (class) accomplishes its task under the hood, as long is it doesn't change the public interface presented to the end user. Perhaps, in the next version of .Net, some new-fangled magical structure that is not an array of characters will be used to implement the string class. The end user may not be aware that this change has even occurred because they can still use the string class in the same way, and if they so desire, could still output the characters to an array with ToCharArray()...even though internally the string is no longer an array of characters.
Yes String type is a character array but string array is not an character array you must have to convert each string in your array in char type so that you can easily reverse its indexes and then convert it into temporary string and then add that string to array to be reversed
Internally, the text is stored as a sequential read-only collection of Char objects.
See Programming Guide Docs
Console.WriteLine(StringHelper.ReverseString("framework"));
Console.WriteLine(StringHelper.ReverseString("samuel"));
Console.WriteLine(StringHelper.ReverseString("example string"));
OR
public static string ReverseString(string s)
{
char[] arr = s.ToCharArray();
Array.Reverse(arr);
return new string(arr);
}

Why does `String.Trim()` not trim the object itself?

Not often but sometimes I need to use String.Trim() to remove whitespaces of a string.
If it was a longer time since last trim coding I write:
string s = " text ";
s.Trim();
and be surprised why s is not changed. I need to write:
string s = " text ";
s = s.Trim();
Why are some string methods designed in this (not very intuitive) way? Is there something special with strings?
Strings are immutable. Any string operation generates a new string without changing the original string.
From MSDN:
Strings are immutable--the contents of a string object cannot be
changed after the object is created, although the syntax makes it
appear as if you can do this.
s.Trim() creates a new trimmed version of the original string and returns it instead of storing the new version in s. So, what you have to do is to store the trimmed instance in your variable:
s = s.Trim();
This pattern is followed in all the string methods and extension methods.
The fact that string is immutable doesn't have to do with the decision to use this pattern, but with the fact of how strings are kept in memory. This methods could have been designed to create the new modified string instance in memory and point the variable to the new instance.
It's also good to remember that if you need to make lots of modifications to a string, it's much better to use an StringBuilder, which behaves like a "mutable" string, and it's much more eficient doing this kind of operations.
As it is written in MSDN Library:
A String object is called immutable (read-only), because its value
cannot be modified after it has been created. Methods that appear to
modify a String object actually return a new String object that
contains the modification.
Because strings are immutable, string manipulation routines that
perform repeated additions or deletions to what appears to be a single
string can exact a significant performance penalty.
See this link.
In addition to all the good answers, I also feel that the reason being Threadsaftey.
Lets say
string s = " any text ";
s.Trim();
When you say this there is nothing stopping the other thread from modifying s. If the same string is modified, lets say the other thread remove 'a' from s, then what is the result of s.Trim()?
But when it returns the new string, though it is being modified by the other thread, the trim can make a local copy modify it and return modified string.

Inserting a string into a list<string> element?

I'm using this line of code to insert a value from an array into a certain line, in a list of lines.
lineList[LineNumber].Insert(lineList[LineNumber].Count(), pArray[i]);
After debugging all the variables are correct, the pArray is passed in as a parameter and lineList is inherited from another class. I can't see why this wouldnt work, all the lines that are added are just empty?
This is because .NET strings are immutable; string.Insert returns a new string, rather than modifying an existing one. If you need to modify the string, add an assignment, like this:
lineList[LineNumber] = lineList[LineNumber]
.Insert(lineList[LineNumber].Count(), pArray[i]);
This should be equivalent to
lineList[LineNumber] += pArray[i];

C# Regex.Replace (or String.Replace) only partially works

I run a repeated Regex.Replace over a string, replacing certain "variables" with their "values". Thing is, some get replaced and some don't!
I have to analyze certain batch files (IBM JCL batch language, to be precise) and search them for JCL variables (rules: JCLvariable starts with "&" and ends with space; ","; "." or other variable start, that being "&"). My functions is supposed to take the string with variables and array of variables-and-their-values as an input; then search the string and replace JCL variables with their values. So is I run a forcycle and for each value-variable struct in array, I run Regex.Replace (in order to prevent the "&TOSP." being misplaced for "&TO." and adhere to JCL var rules, see above):
private string ReplaceDSNVarsWithValues(string _DSN,JCLvar[] VarsAndValues)
{
//FIXME: nefunguje pro TIPfile a nebere všechny &var
for(int Fa=0;Fa<VarsAndValues.Length/2;++Fa)
{
_DSN = Regex.Replace(_DSN, "&"+VarsAndValues[Fa].JCLvariable+"[^A-Za-z0-9]", VarsAndValues[Fa].JCLvalue);
}
return _DSN;
}
Eg. I have this as a string to replace:
string _DSN = "&TOSP..COPY.&SYSTEM..SP&APL..BVSIN.SAVEC.D&MES.&DEN..V&VER.K99";
And then I have an array of struct containing couples of variable and value, eg.
JCLvar[1].variable = "APL",JCLvar[1].value = "PROD"
Combine that and it should result in the "SP&APL." part changing to "SPPROD".
The problem is, only SOME of the variables get replaced:
&TOSP..COPY.&SYSTEM..SP&APL..BVSIN.SAVEC.D&MES.&DEN..V&VER.K99 gets changed to SP.COPY.DBA0.SPPROD.BVSIN.SAVEC.D&MESDENV&VER.K99 as it should (disregard &MES,&DEN - these are not filled in the ValsAnd Values array and therefore don't get replaced), but in
&TO..#ZDSK99.PODVYP.M&MES.U&DEN..SUC.RES, the "&TO." doesn't get changed at all - although it exists in the array and via debugging, I see that it is being passed to the regex /but it doesn't get changed/.
How the heck it comes SOME variables get replaced and others don't?
In the array VarsAndValues, order of variables matters, because if "TOSP" is first, it gets replaced and "&TO" does not, while if "TO" is first, it gets replaced and "&TOSP" doesn't; therefore, I got suspicion that Regex.Replace somehow fails to do repeated replace on similar expressions/variables in the same string OR fails to recognize the variable/expression to be replaced - but I see no reason for the first possibility and the second one is impossible, as the replaced expressions clearly stay there.
//Note - I know it's certainly not nice coding, but it's more a single-purpose script I wrote to save me weeks of manual work than anything else
I don't see anything wrong with your regex. But why are you iterating over only half of VarsAndValues?
for(int Fa=0;Fa<VarsAndValues.Length/2;++Fa)
tells me you're stopping halfway through the array, so if TOSP happens to fall in the second half, it won't be replaced.

Why string.Replace("X","Y") works only when assigned to new string?

I guess it has to do something with string being a reference type but I dont get why simply string.Replace("X","Y") does not work?
Why do I need to do string A = stringB.Replace("X","Y")? I thought it is just a method to be done on specified instance.
EDIT: Thank you so far. I extend my question: Why does b+="FFF" work but b.Replace does not?
Because strings are immutable. Any time you change a string .net creates creates a new string object. It's a property of the class.
Immutable objects
String Object
Why doesn't stringA.Replace("X","Y") work?
Why do I need to do stringB = stringA.Replace("X","Y"); ?
Because strings are immutable in .NET. You cannot change the value of an existing string object, you can only create new strings. string.Replace creates a new string which you can then assign to something if you wish to keep a reference to it. From the documentation:
Returns a new string in which all occurrences of a specified string in the current instance are replaced with another specified string.
Emphasis mine.
So if strings are immutable, why does b += "FFF"; work?
Good question.
First note that b += "FFF"; is equivalent to b = b + "FFF"; (except that b is only evaluated once).
The expression b + "FFF" creates a new string with the correct result without modifying the old string. The reference to the new string is then assigned to b replacing the reference to the old string. If there are no other references to the old string then it will become eligible for garbage collection.
Strings are immutable, which means that once they are created, they cannot be changed anymore. This has several reasons, as far as I know mainly for performance (how strings are represented in memory).
See also (among many):
http://en.wikipedia.org/wiki/Immutable_object
http://channel9.msdn.com/forums/TechOff/58729-Why-are-string-types-immutable-in-C/
As a direct consequence of that, each string operation creates a new string object. In particular, if you do things like
foreach (string msg in messages)
{
totalMessage = totalMessage + message;
totalMessage = totalMessage + "\n";
}
you actually create potentially dozens or hundreds of string objects. So, if you want to manipulate strings more sophisticatedly, follow GvS's hint and use the StringBuilder.
Strings are immutable. Any operation changing them has to create a new string.
A StringBuilder supports the inline Replace method.
Use the StringBuilder if you need to do a lot of string manipulation.
Why "b+="FFF"works but the b.replace is not
Because the += operator assigns the results back to the left hand operand, of course. It's just a short hand for b = b + "FFF";.
The simple fact is that you can't change any string in .Net. There are no instance methods for strings that alter the content of that string - you must always assign the results of an operation back to a string reference somewhere.
Yes its a method of System.String. But you can try
a = a.Replace("X","Y");
String.Replace is a shared function of string class that returns a new string. It is not an operator on the current object. b.Replace("a","b") would be similar to a line that only has c+1. So just like c=c+1 actually sets the value of c+1 to c, b=b.Replace("a","b") sets the new string returned to b.
As everyone above had said, strings are immutable.
This means that when you do your replace, you get a new string, rather than changing the existing string.
If you don't store this new string in a variable (such as in the variable that it was declared as) your new string won't be saved anywhere.
To answer your extended question, b+="FFF" is equivalent to b = b + "FFF", so basically you are creating a new string here also.
Just to be more explicit. string.Replace("X","Y") returns a new string...but since you are not assigning the new string to anything the new string is lost.

Categories