Click here to Skip to main content
Click here to Skip to main content

Few extension methods of String concatenation in C#

By , 19 Jun 2011
 
String concatenation
 
About string concatenation, there are already many articles that have been posted in the web. There are many arguments about string concatenation, for example some people say we should not use +, some says use string.join or StringBuilder. I think all are right because usage of different techniques depend on the situation and expected performance really. I reflect the string.concat method using .NET reflector then found
return (arg0.ToString() + arg1.ToString());
code in where they use + so then what's wrong with the + ? Of course, there are performance issues with +.
 
So I have created few extensions of string to do the concatenation operation which I include below:
 
public static class StringExtensions
{
 
        public static string JoinWithSeparator(this string baseItem, string firstItem, string separator = default(string))
        {
            return string.Join(separator: separator, value: new[] { baseItem, firstItem });
        }
 
        public static string JoinWithSeparator(this string baseItem, string firstItem, string secondItem, string separator = default(string))
        {
            return string.Join(separator: separator, value: new[] { baseItem, firstItem, secondItem });
        }
 
        public static string JoinWithSeparator(this string baseItem, string[] items, string separator = default(string))
        {
            return string.Join(separator, new[] { baseItem, string.Join(separator: separator, value: items) });
        }
 
        public static string JoinWith(this string baseItem, string[] items, string separator = default(string))
        {
            var builder = new StringBuilder();
 
            Array.ForEach(items,
                item =>
                {
                    builder.Append(value: item).Append(separator);
                });
 
            return ReferenceEquals(separator, default(string)) ? builder.ToString() : builder.ToString().TrimEnd(separator.ToCharArray());
        }
 
        public static string JoinWithDifferentTypes<T1, T2, T3>(this string baseItem, Tuple<T1, T2, T3> tupleOfJoinableItems)
            where T1 : struct
            where T2 : struct
            where T3 : class
        {
 
            var builder = new StringBuilder();
            builder.Append(baseItem).Append(tupleOfJoinableItems.Item1).Append(tupleOfJoinableItems.Item2);
 
            return ReferenceEquals(tupleOfJoinableItems.Item3, null) ? builder.ToString() : builder.Append(tupleOfJoinableItems.Item3.ToString()).ToString();
        }
}
 
In the above code, I used string.Join and StringBuilder to join with given strings and also I wrote extension named JoinWithDifferentTypes by which I tried to use multiple types to join into one string item. In the JoinWithDifferentTypes method, I could also use:
 
return string.Format("{0}{1}{2}{3}", baseItem, tupleOfJoinableItems.Item1, tupleOfJoinableItems.Item2, tupleOfJoinableItems.Item3);
 
to describe the usage of the above extension methods I used following code blocks:
 
static void Main(string[] args)
{
            string[] items = new string[] { "One-", "Two-", "Three" };
            string baseItem = "Zero";
 
            Console.WriteLine("Results :\n {0}\n {1}\n {2}\n {3}\n {4}\n {5}\n {6}\n {7}",
                new object[]
                {
                    baseItem.JoinWithSeparator("One", Definitions.Separator),
                    baseItem.JoinWithSeparator("One", "Two", Definitions.Separator),
                    baseItem.JoinWithSeparator(new[] { "One", "Two" }, Definitions.Separator),
                    baseItem.JoinWith(Definitions.Topics.Split(new[] { ',' }), Definitions.Separator),
                    baseItem.JoinWith(Definitions.Topics.Split(new[] { ',' })),
                    baseItem.JoinWithDifferentTypes<int, char, object>(new Tuple<int, char, object>(1, 'C', null)),
                    baseItem.JoinWithDifferentTypes<int, char, Person>(new Tuple<int, char, Person>(1, 'C', new Person() { Name = "Name", Address = "Address" }))
                });
            Console.ReadKey();
}
 
JoinWithSeparator
 
There are three overloaded versions and all of those have a common behavior which is the separator and it is optional. Besides that, if I want to join with a single item, I could use JoinWithSeparator extension for example, "JoinWith".JoinWithSeparator("Me") or if want to add two items with separator, then "JoinWith".JoinWithSeparator("A","B",Definitions.Separator). This extension is preferable for the circumstances where we need to add One or Two items with baseItem.
 
JoinWith
 
The JoinWith extension will take an array of string tokens and will add those with the baseitem. If we need to add many items, then we should use this extension.
 
JoinWithDifferentTypes
 
If we want to add different types of items into the baseItem (which is string in here), then we can use this one.
 
and some other related classes I used:
 
public class Person
{
    public string Name { get; set; }
    public string Address { get; set; }
 
    public override string ToString()
    {
       return Name.JoinWith(Address);
    }
}
 
public class Definitions
{
    public const string
           Separator = "-",
           Topics = "Programming, Music, Documentary";
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Mohammad A Rahman
Software Developer
Australia Australia
Member
Designer and Architect.
Author of the Expert C# 5.0: with the .NET 4.5 Framework book

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralRe: Well, hoorah for the compiler! I just checked and string + s...membercameronsstone22 Jun '11 - 15:19 
Well, hoorah for the compiler! I just checked and string + string + object also uses String.Concat.
 
However it is the object overload that it calls. I just did some very rough profiling using LinqPad and calling string + string + object.ToString() is almost 40% faster. Here's my profiling code:
 
class myObject
{
string s = "myObject";
public string ToString(){ return s; }
}
 
void Main()
{
DateTime start = DateTime.Now;
for (int i = 0; i < 100000000; ++i)
{
string str1 = "1";
string str2 = "2";
myObject myObject1 = new myObject();
string str1And2And3 = str1 + str2 + myObject1.ToString();
}
DateTime.Now.Subtract(start).Dump();
 
start = DateTime.Now;
for (int i = 0; i < 100000000; ++i)
{
string str1 = "1";
string str2 = "2";
myObject myObject1 = new myObject();
string str1And2And3 = str1 + str2 + myObject1;
}
DateTime.Now.Subtract(start).Dump();
}

GeneralHi there, it is good idea too. ThanksmemberMohammad A Rahman20 Jun '11 - 22:40 
Hi there, it is good idea too. Thanks
GeneralRather than the multiple JoinWithSeparator methods, why not ...memberREEDY83720 Jun '11 - 22:06 
Rather than the multiple JoinWithSeparator methods, why not just use params:
 
public static string JoinWithSeparator(this string baseItem, string separator = default(string), params string[] items)
{
return string.Join(separator, new[] { baseItem, string.Join(separator, items) });
}
GeneralJust checked what you said about string.Concat and I was hor...membercameronsstone1 Jun '11 - 18:42 
Just checked what you said about string.Concat and I was horrified to see you were right, but only if the arguments are *not* strings: string.Concat(Object, Object, etc). string.Concat(string, string, etc) is much better: a single memory allocation, with wstrcpy to fill it in from the source strings.
 
So the message here is clear: if you want to use string.Concat, call ToString on all your arguments!
GeneralRe: Don't be too horrified by string.Concat using + to concatena...memberjim.horvath22 Jun '11 - 14:15 
Don't be too horrified by string.Concat using + to concatenate two items... using + to concat between _only_ two (2) objects is okay! The performance problem (could) arise when you use + between _more than 2 items_. And when it comes to strings, this should rarely be an issue with modern .NET because the compiler will optimize many of your long-chained string adds - read to the end for the proof. But first - if you understand a) string's immutability (a string object can't be changed once it's created) and b) how multiple + expressions work, then it should make sense that where:
 
string str1 = "1";
string str2 = "2";
string str3 = "3";
 
then this statement creates one new string and stores it in the variable "combined":
 
string combined = str1 + str2;
 
but this next statement creates 2 new strings before storing the result in combined, and one of them is immediately garbage that needs to be collected!
 
string combined = str1 + str2 + str3;
 
One of them is immediately garbage because:
- first str1 and str2 are concat'd, making a string I'll call TEMPSTRING.
- then TEMPSTRING is concat'd with str3 and the result is stored in combined.
 
This is what makes + with strings potentially inefficient - that need for TEMPSTRING with chained + creates garbage which needs to be collected, but it can be avoided if you use string.Concat or StringBuilder. This example theoretically makes TWO temporary strings that are immediately garbage:
 
string combined = str1 + str2 + str3 + str4;
 
Breakdown:
- TEMPSTRING1 = str1 + str2
- TEMPSTRING2 = TEMPSTRING1 + str3
- combined = TEMPSTRING2 + str4
 
If you've read this far then you must be interested. Smile | :) Besides using + between 2 strings being okay, there are many cases where the C# compiler will replace chained + expressions between strings with string.Concat for you! For proof, compile the following code and use Reflector, or put it into LINQPad and look at the "IL" tab - you'll see that the last statement adding 3 strings is replaced by a call to string.Concat:
 
string str1 = "1";
string str2 = "2";
string str3 = "3";
string str1And2And3 = str1 + str2 + str3;
 
If you use + between more than 4 strings, the compiler will simply allocate an array, put all your strings in it, and pass that to string.Concat. As long as you are using + between string objects, the compiler does a lot of work to avoid creating less-than-optimal code. It may even do it if you're using + between strings and non-strings. I haven't checked. Overall, my point is:
 
- When using a modern .NET compiler, you don't need to avoid + between strings as much as was recommended back in the early days of .NET. In the earlier days of .NET it was a very valid concern, but I know 3.5 and 4.0 do these optimizations of string concatenation for you. When in doubt, make a test assembly with the version you are using and use Reflector or JustDecompile to see the results - in my testing with 3.5 and 4.0, you don't even need to do a "Release" optimized build - it does it in "Debug" builds too.
 
- Be sensible - if you've got a 100-line function that builds a string, then use StringBuilder. The compiler can/will only optimize obvious cases.
 
- Use a profiler to find cases where your code is slow! Later! Make the code work, and then make it right. In the words of Donald Knuth: "We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil"

GeneralThank you so much......memberPritesh Aryan23 May '11 - 23:58 
Thank you so much......
GeneralRe: happy to know, it helps.memberMohammad A Rahman24 May '11 - 0:12 
happy to know, it helps.
Generalin below code &lt;pre&gt;public static string JoinWithSepara...memberPritesh Aryan23 May '11 - 20:05 
in below code
<pre>public static string JoinWithSeparator(this string baseItem, string firstItem, string separator = default(string))
{
return string.Join(separator: separator, value: new[] { baseItem, firstItem });
}</pre>
 

 
new[]{...}
seems strange........new of which type?... could you please elaborate.....what is it?
 
Thanks......
GeneralRe: Hi there, new[]{...} its Implicit Typed Array. From the meth...memberMohammad A Rahman23 May '11 - 22:26 
Hi there, new[]{...} its Implicit Typed Array. From the method signature we can see baseItem and firstItem both are string so in this situation new[] will be a array of strings. Please see Implicityly Typed Arrays section of from http://msdn.microsoft.com/en-us/library/ms364047(v=vs.80).aspx. thanks.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130516.1 | Last Updated 19 Jun 2011
Article Copyright 2011 by Mohammad A Rahman
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid