Similarly to passing a list through a function and adding elements to it, I want to pass a string and add characters to it. However, I do not want to change the reference.
Func(List myList) {
myList.Append("hello");
}
Func(List myList) {
myList = new List();
}
It's like the distinction between the two functions above. In one case you're adding an element to an existing reference to an object, in the other case you are changing the object that is referenced to.
With strings, I have noticed you always(?) change the object that is referenced to. Every solution i've found takes two or more strings, adds them together and returns a new string.
Is there a way to use the same string instance and add one or more characters to this specific instance?
With strings, I have noticed you always(?) change the object that is referenced to.
Because strings are immutable. You can't change a string in .NET. That opens the door to many optimizations (such as string interning), but also has performance issues when you want to build a long string by parts - many allocations and copyings of memory (to concatenate two strings, you have to allocate a third in the length of the two together, then copy them).
So Microsoft created System.Text.StringBuilder. The idea is to create mutable string. The basic methods are Append() (which appends some data, often primitive types) and AppendFormat() (similar to string.Format()). Then you get a normal string by calling to ToString():
void Func(StringBuilder s)
{
s.Append("Hi everyone!");
}
var s = new StringBuilder();
s.Append("a StringBuilder.");
Func(s);
s.ToString(); // "a StringBuilder.Hi everyone!"
Is there a way to use the same string instance and add one or more
characters to this specific instance?
No, but you can do it by using StringBuilder. Pass instance of StringBuilder to a function and append any string to it, it will add string but will refer to same instance of StringBuilder class
public void AppendString(StringBuilder sb) {
sb.Append("hello");
}
This is because string type is mutable, whenever you assign new value to string it creates new string object in memory, but StringBuilder is immutable, it is reference type. StringBuilder modifies without creating new object.
You can try below code,
public static void Main()
{
StringBuilder sb = new StringBuilder("Default Text");
Console.WriteLine($"Before function call: {sb.ToString()}");
AppendString(sb); //Function call
Console.WriteLine($"After function call: {sb.ToString()}");
}
public static void AppendString(StringBuilder sb)
{
sb.Append(" Hello world");
Console.WriteLine($"Inside function: {sb.ToString()}");
}
Output:
Before function call: Default Text
Inside function: Default Text Hello world
After function call: Default Text Hello world
.Net fiddle
I would suggest you to read string vs StringBuilder
You can achieve this by passing string parameter as reference. Please refer to the following code snippet.
static void Main(string[] args)
{
string input = "input";
AddString(ref input);
System.Console.WriteLine(input);
}
private static void AddString(ref string input)
{
input += "_edited";
}
You will need to use ref keyword in both the cases while defining and passing method parameter. Hope it helps.
Related
I've been having a little problem with sharing variables to different objects, I was hoping to understand what I'm doing wrong and find a solution to the problem, I'm sort of new to programming using the object oriented programming language (C#) and I don't know what I'm doing wrong when it comes to that detail.
What I'm trying to do basically is to create a method which receives a user's input of some words as a string, it removes excess spaces from the string and creates a string array which holds every word within the string when it is seperated by a space.
The problem here is that the "return words;" at the end of the "RemoveSpace()" method isn't returning the value to "Test()" at all.
(I made sure to check that it was actually working using the debugger, but the RemoveSpace function is definitely working, just only within the method, and the returned value is seemingly ignored by the Test() method.)
(Also, to use Regex, use the "System.Text.RegularExpressions;" library)
What should I do? I've been racking my brain on it for a while and I'm out of ideas,
I'd much appreciate some help
public static class Reverso
{
static void Main(string[] args)
{
//User inputs the words as a string
string words = Console.ReadLine();
//Activates the Test object
Test(words);
}
public static void Test(string words)
{
//Activates the RemoveSpace object.
//It should receive the returned
//value here, but not working
RemoveSpace(words);
//Takes words into a string array
//seperated by spaces
string[] parts = words.Split(' ');
//Shows the result
Console.WriteLine(words);
}
public static string RemoveSpace(string words)
{
//Using regex in order to remove more
//than 1 space between words and characters
Regex regex = new Regex(#"[ ]{2,}", RegexOptions.None);
words = regex.Replace(words, #" ");
//Should return the value of the word
//to the Test object, *not working*
return words;
}
}
If you want to reassign to words inside RemoveSpace, you need to pass the variable by reference:
public static string RemoveSpace(ref string words) // Use ref to pass by reference
Then inside Test, you would call the method like this:
RemoveSpace(ref words);
Without passing by reference, the words argument of RemoveSpace is a separate variable to the words variable in the calling method, so reassigning only affects the scope of RemoveSpace.
The usual approach would be to reassign the string that is returned from RemoveSpace inside Test:
public static void Test(string words)
{
words = RemoveSpace(words);
I call a few VBA methods from my C# project. This has caused me to repeat code in my project. So I created a C# method for the few that take the same amount of parameters but a few take different amounts. So I thought about a solution, all the parameters that I pass in are strings, so what if I pass in to my C# method a string array, then convert that string array in to individual strings in the VBA subprocedure call. This is what I have:
private static void RunVBAMethod(Excel.Application excelApp, string logFile, string vBAMethod, string [] args, out string errorType)
{
errorType = CSharpError;
var VbaCrashed = excelApp.Run(vBAMethod, ConvertStringArrayToString(args));
if (VbaCrashed != "False")
{
errorType = VBAError;
throw new Exception(VbaCrashed);
}
}
Here is my ConvertArrayToString method:
private static string ConvertStringArrayToString(string[] array)
{
// Concatenate all the elements into a StringBuilder.
StringBuilder builder = new StringBuilder();
foreach (string value in array)
{
builder.Append(value);
builder.Append(',');
}
return builder.ToString();
}
Then I call it like this:
RunVBAMethod(excelApp, LogFile, "CleanMRP", new string[] { CurrentWorkbook.TimePeriod, CurrentWorkbook.Version, RemoveSpace(CurrentWorkbook.ReportType), CurrentWorkbook.MainMRPFilePath + CurrentWorkbook.FileName, HeaderRow.ToString(), CurrentWorkbook.DataPath }, out ExcelCrashed);
When I run it, it crashes on the excelApp.Run line saying Parameter not optional. Is, what I am trying to do even possible? Am I looking at the wrong way to do, if it is? or am I missing something so small?
I'm learning C# and C and this C# code is giving me an error I don't understand. I'm reading about extension methods and this code is giving the error: No overload for method 'WriteTextToConsole' takes 1 arguments. As you can see, it takes exactly 1 arguments? I created the variables c and count only to be able to construct the string object. So I could try the extension in the String class. Is it right understood that the way you create an extension method: is to precede the parameter with the "this" keyword and the parameter is of the type of class to be extended?
The code is here:
Console.WriteLine();
M.WriteTextToConsole("Hello, world. Programming in C# is fun");
char c = 'A';
int count = 14;
String str = new String(c, count);
str.WriteTextToConsole("This is a string");
The method is here:
static class M
{
public static void WriteTextToConsole(this string text)
{
Console.WriteLine(text);
}
}
you need to call it as str.WriteTextToConsole();. In this case str would be passed as a single argument to M.WriteTextToConsole() method
When you call the extension method on the string the "this string text" parameter refers to the string itself,for example if it where "this Bitmap b" it would be an extension method for the bitmap and assuming you had created a bitmap object named bit the call would be bit.WriteTextToConsole().If you want to had other parameters you need to add those to to the method declaration and to make so it is an option for the caller make it with the params keyword like so:
static class M
{
public static void WriteTextToConsole(this string text,params string[] str)
{
if (str.Length > 0)
{
//do something with extra string or strings
//you can make params Object[] but for this
//example i choose string[]
Console.WriteLine(text);
return;
}
Console.WriteLine(text);
}
}
Just remenber the this keyword must be the first parameter,refering to the type you are extending.
In the case of having optional strings i left the code with the duplicate console.WriteLine(text) you can rewrite it if you in both cases want the string displayed in the console(just remove the return and console writeline above it).
Im still learning in C#, and there is one thing i cant really seem to find the answer to.
If i have a string that looks like this "abcdefg012345", and i want to make it look like "ab-cde-fg-012345"
i tought of something like this:
string S1 = "abcdefg012345";
string S2 = S1.Insert(2, "-");
string S3 = S2.Insert(6, "-");
string S4 = S3.Insert.....
...
..
Now i was looking if it would be possible to get this al into 1 line somehow, without having to make all those strings.
I assume this would be possible somehow ?
Whether or not you can make this a one-liner (you can), it will always cause multiple strings to be created, due to the immutability of the String in .NET
If you want to do this somewhat efficiently, without creating multiple strings, you could use a StringBuilder. An extension method could also be useful to make it easier to use.
public static class StringExtensions
{
public static string MultiInsert(this string str, string insertChar, params int[] positions)
{
StringBuilder sb = new StringBuilder(str.Length + (positions.Length*insertChar.Length));
var posLookup = new HashSet<int>(positions);
for(int i=0;i<str.Length;i++)
{
sb.Append(str[i]);
if(posLookup.Contains(i))
sb.Append(insertChar);
}
return sb.ToString();
}
}
Note that this example initialises StringBuilder to the correct length up-front, therefore avoiding the need to grow the StringBuilder.
Usage: "abcdefg012345".MultiInsert("-",2,5); // yields "abc-def-g012345"
Live example: http://rextester.com/EZPQ89741
string S1 = "abcdefg012345".Insert(2, "-").Insert(6, "-")..... ;
If the positions for the inserted strings are constant you could consider using string.Format() method. For example:
string strTarget = String.Format("abc{0}def{0}g012345","-");
string s = "abcdefg012345";
foreach (var index in [2, 6, ...]
{
s = s.Insert(index, "-");
}
I like this
StringBuilder sb = new StringBuilder("abcdefg012345");
sb.Insert(6, '-').Insert(2, '-').ToString();
String s1 = "abcdefg012345";
String seperator = "-";
s1 = s1.Insert(2, seperator).Insert(6, seperator).Insert(9, seperator);
Chaining them like that keeps your line count down. This works because the Insert method returns the string value of s1 with the parameters supplied, then the Insert function is being called on that returned string and so on.
Also it's worth noting that String is a special immutable class so each time you set a value to it, it is being recreated. Also worth noting that String is a special type that allows you to set it to a new instance with calling the constructor on it, the first line above will be under the hood calling the constructor with the text in the speech marks.
Just for the sake of completion and to show the use of the lesser known Aggregate function, here's another one-liner:
string result = new[] { 2, 5, 8, 15 }.Aggregate("abcdefg012345", (s, i) => s.Insert(i, "-"));
result is ab-cd-ef-g01234-5. I wouldn't recommend this variant, though. It's way too hard to grasp on first sight.
Edit: this solution is not valid, anyway, as the "-" will be inserted at the index of the already modified string, not at the positions wrt to the original string. But then again, most of the answers here suffer from the same problem.
You should use a StringBuilder in this case as Strings objects are immutable and your code would essentially create a completely new string for each one of those operations.
http://msdn.microsoft.com/en-us/library/2839d5h5(v=vs.71).aspx
Some more information available here:
http://www.dotnetperls.com/stringbuilder
Example:
namespace ConsoleApplication10
{
class Program
{
static void Main(string[] args)
{
StringBuilder sb = new StringBuilder("abcdefg012345");
sb.Insert(2, '-');
sb.Insert(6, '-');
Console.WriteLine(sb);
Console.Read();
}
}
}
If you really want it on a single line you could simply do something like this:
StringBuilder sb = new StringBuilder("abcdefg012345").Insert(2, '-').Insert(6, '-');
As is described at Microsoft Site ,String.Format arranges some String Variables into a single String and is another way how to concate string's in c#.
string.Format("Name = {0} Surname = {1}",name,surname);
My question is how does this work ?
Is this method a Special method ,and can i create a method similar to this one which accepts at every {n} only an Integer .
Or is this method interpreted in a different way by compiler ,if yes than how does the compiler accesses this method .
If it's possible i would like to see ,how does the compiler interpret this Method.
PS : How does it work ,when you can send as much parameters as you want to a method ?
[EDIT]
Does it mean ,that String.Format takes the first Parameter and filter's into with a Regex or Whatever tool (Split etc) to get where {Number} is and places there a String token from second params portion ?
Sending a variable number of parameters to a method is done like this:
public static string MyStringFormat(string formatString, params object [] args)
{
}
You can now pass as many parameters as you like to this:
MyStringFormat("{0}{1}",42,"Hello World")
MyStringFormat("{0}{1}{2}",42,"Hello World",999.9)
Within the method, these arguments are simply an array (of object in this case).
here are the docs on the params keyword.
As for writing you own method to accept numeric input like Format does, this would be one way (using regular expressions):
public static string MyStringFormat(string formatString, params object[] args)
{
var regex = new Regex("{([0-9]*)}");
return regex.Replace(formatString,m =>
{
int index = int.Parse(m.Groups[1].Value);
if(index<args.Length)
return args[index].ToString();
return String.Empty;
});
}
Live example: http://rextester.com/rundotnet?code=OMZC13551
It is a normal function.
It parses the string and calls ToString on the incoming parameters (if needed) in order to construct the new string.
The signature of the overload you have in your example is:
public static string Format(
string format,
params Object[] args
)
There is nothing to stop you from creating your own (though I would probably just delegate to the built in string.Format).
Use params: http://msdn.microsoft.com/en-us/library/w5zay9db.aspx
there is no magic there Cody, look at this method:
public static void UseParams(params int[] list)
{
for (int i = 0 ; i < list.Length; i++)
{
Console.WriteLine(list[i]);
}
Console.WriteLine();
}
you can call it passing as many int you like, it's the params parameter type :)
Edit:
params is very useful it allows us, for example, to pass to our logging wrapper all method's parameters values in a dynamic way without knowing how many of them each method has, the logger will then dump all those values one by one using Reflection to find out the parameter name as well.
The braces in the string are placeholders and a number within that denotes the index of argument it is to be replaced with.
Format is of type (string format, params object[] args) and it is the index in this object[] which is helpful.
(I think it internally uses the StringBuilder.AppendFormat) for substituting those values)
The signature of String.Format looks like this:
public static string Format (string format, params Object[] args)
Note the second parameter, marked with the params keyword. That one provides the functionality to add multiple parameters when calling the function. Inside the function you can access the parameters by index or iterating over args array:
public static string Format (string format, params Object[] args)
{
foreach (Object o in args)
Console.WriteLine(o);
}
Have a look at the C# Reference.