CodeSOD: The String Buildulator

"Don't concatenate long strings," is generally solid advice in most languages. Due to internal representations, strings are frequently immutable and of a fixed length, so a block like this:

string s = getSomeString(); s = s + "some suffix";

creates three strings- the original, the suffix, and the third, concatenated string. Keep spamming instances, especially long ones, if you want to stress test your garbage collector.

While languages will do their best to optimize those kinds of operations, the general advice is to use string builders which can minimize those allocations and boost performance.

Or, you can do what Richard B's predecessor did, and abuse the heck out of string interpolation in C#.

StreamWriter sw = new StreamWriter(filename); #region Export file header string header = ""; header = "Title"; header = $"{header},\"First Name\""; header = $"{header},\"Middle Name\""; header = $"{header},\"Last Name\""; header = $"{header},Suffix"; header = $"{header},Company"; header = $"{header},Department"; header = $"{header},\"Job Title\""; header = $"{header},\"Business Street\""; header = $"{header},\"Business Street 2\""; header = $"{header},\"Business Street 3\""; header = $"{header},\"Business City\""; header = $"{header},\"Business State\""; header = $"{header},\"Business Postal Code\""; header = $"{header},\"Business Country/ Region\""; header = $"{header},\"Home Street\""; header = $"{header},\"Home Street 2\""; header = $"{header},\"Home Street 3\""; header = $"{header},\"Home City\""; header = $"{header},\"Home State\""; header = $"{header},\"Home Postal Code\""; header = $"{header},\"Home Country/ Region\""; header = $"{header},\"Other Street\""; header = $"{header},\"Other Street 2\""; header = $"{header},\"Other Street 3\""; header = $"{header},\"Other City\""; header = $"{header},\"Other State\""; header = $"{header},\"Other Postal Code\""; header = $"{header},\"Other Country/ Region\""; header = $"{header},\"Assistant's Phone\""; header = $"{header},\"Business Fax\""; header = $"{header},\"Business Phone\""; header = $"{header},\"Business Phone 2\""; header = $"{header},Callback"; header = $"{header},\"Car Phone\""; header = $"{header},\"Company Main Phone\""; header = $"{header},\"Home Fax\""; header = $"{header},\"Home Phone\""; header = $"{header},\"Home Phone 2\""; header = $"{header},ISDN"; header = $"{header},\"Mobile Phone\""; header = $"{header},\"Other Fax\""; header = $"{header},\"Other Phone\""; header = $"{header},Pager"; header = $"{header},\"Primary Phone\""; header = $"{header},\"Radio Phone\""; header = $"{header},\"TTY/TDD Phone\""; header = $"{header},Telex"; header = $"{header},Account"; header = $"{header},Anniversary"; header = $"{header},\"Assistant's Name\""; header = $"{header},\"Billing Information\""; header = $"{header},Birthday"; header = $"{header},\"Business Address PO Box\""; header = $"{header},Categories"; header = $"{header},Children"; header = $"{header},\"Directory Server\""; header = $"{header},\"E - mail Address\""; header = $"{header},\"E - mail Type\""; header = $"{header},\"E - mail Display Name\""; header = $"{header},\"E-mail 2 Address\""; header = $"{header},\"E - mail 2 Type\""; header = $"{header},\"E - mail 2 Display Name\""; header = $"{header},\"E-mail 3 Address\""; header = $"{header},\"E - mail 3 Type\""; header = $"{header},\"E - mail 3 Display Name\""; header = $"{header},Gender"; header = $"{header},\"Government ID Number\""; header = $"{header},Hobby"; header = $"{header},\"Home Address PO Box\""; header = $"{header},Initials"; header = $"{header},\"Internet Free Busy\""; header = $"{header},Keywords"; header = $"{header},Language"; header = $"{header},Location"; header = $"{header},\"Manager's Name\""; header = $"{header},Mileage"; header = $"{header},Notes"; header = $"{header},\"Office Location\""; header = $"{header},\"Organizational ID Number\""; header = $"{header},\"Other Address PO Box\""; header = $"{header},Priority"; header = $"{header},Private"; header = $"{header},Profession"; header = $"{header},\"Referred By\""; header = $"{header},Sensitivity"; header = $"{header},Spouse"; header = $"{header},\"User 1\""; header = $"{header},\"User 2\""; header = $"{header},\"User 3\""; header = $"{header},\"User 4\""; header = $"{header},\"Web Page\""; #endregion Export file header sw.WriteLine(header);

The real killer to this is that there's no need for string concatenation at all. There's no reason one needs to WriteLine the entire header at once. sw.Write("Title,"); Also, string interpolation is almost always more expensive than straight concatenation, and harder for compilers to optimize. I'm not about to benchmark this disaster to prove it, but I suspect this is going to be pretty much the most expensive option.

And don't worry, the same basic process follows for each individual row they're outputting:

string contactRow = ""; HtmlToText htmlToText = new HtmlToText(); bool extendedPropRetrieved = false; #region Extract properties for export file if (contact.CompleteName != null) contactRow = $"\"{contact.CompleteName.Title}\""; // Title else contactRow = $""; contactRow = $"{contactRow},\"{contact.GivenName}\""; // First name contactRow = $"{contactRow},\"{contact.MiddleName}\""; // Middle name contactRow = $"{contactRow},\"{contact.Surname}\""; // Last name if (contact.CompleteName != null) contactRow = $"{contactRow},\"{contact.CompleteName.Suffix}\""; //Suffix else contactRow = $"{contactRow},"; contactRow = $"{contactRow},\"{contact.CompanyName}\""; // Company contactRow = $"{contactRow},\"{contact.Department}\""; // Department contactRow = $"{contactRow},\"{contact.JobTitle}\""; // Job title if (contact.PhysicalAddresses.Contains(PhysicalAddressKey.Business)) { contactRow = $"{contactRow},\"{contact.PhysicalAddresses[PhysicalAddressKey.Business].Street}\""; // Business street contactRow = $"{contactRow},"; // Business street 2 contactRow = $"{contactRow},"; // Business street 3 contactRow = $"{contactRow},\"{contact.PhysicalAddresses[PhysicalAddressKey.Business].City}\""; // Business city contactRow = $"{contactRow},\"{contact.PhysicalAddresses[PhysicalAddressKey.Business].State}\""; // Business state contactRow = $"{contactRow},\"{contact.PhysicalAddresses[PhysicalAddressKey.Business].PostalCode}\""; // Business postalcode contactRow = $"{contactRow},\"{contact.PhysicalAddresses[PhysicalAddressKey.Business].CountryOrRegion}\""; // Business country/region } else { contactRow = $"{contactRow},"; contactRow = $"{contactRow},"; contactRow = $"{contactRow},"; contactRow = $"{contactRow},"; contactRow = $"{contactRow},"; contactRow = $"{contactRow},"; contactRow = $"{contactRow},"; } // ... this goes on for about 600 lines

The physical address else block is something really special, here.

[Advertisement] Keep the plebs out of prod. Restrict NuGet feed privileges with ProGet. Learn more.

This post originally appeared on The Daily WTF.

Leave a Reply

Your email address will not be published.