I consistently have code where I need to pull individual chunks of substrings out of a larger string; while I won't get into details, it's easy to replicate in a proof of concept:
var data = "alja5nerjvnalskjnbaeviunreklvnaslidhfvbaelkjnrfvliasndve";
var open = data.Substring(0, 4);
var inputLength = int.Parse(data.Substring(4, 1));
var input = data.Substring(5, inputLength);
data = data.Substring(5 + inputLength);
...
Now, let's ignore the ellipsis for now and focus on the magic numbers and having to keep track of indices. I'm not a fan of that, I'm sure others aren't either, so a way to make this easier to understand is to remove what we just retrieved from input
, each time we retrieve it:
var data = ...;
// Get the open variable, then remove it from the data.
const int openLength = 4;
var open = input.Substring(0, openLength);
data = data.Remove(0, openLength);
// Get the input length variable, then remove it from the data.
const int expectedInputLength = 1; // Bad naming, I know.
var inputLength = int.Parse(data.Substring(0, expectedInputLength));
data = data.Remove(0, expectedInputLength);
// Get the input variable, then remove it from the data.
var input = data.Substring(0, inputLength);
data = data.Remove(0, inputLength);
Unfortunately, this way gets quite verbose and leaves developers leaning towards the original snippet, which is fine, it's just harder to manage (in my opinion). However, I've decided to create an extension method for strings that handles this use case in a more efficient way:
public static string Substring(this string input, int startingIndex, int length, ref string removeFrom) {
var substring = input.Substring(startingIndex, length);
removeFrom = removeFrom.Remove(startingIndex, length);
return substring;
}
The usage changes the previously verbose code back to the original snippet's form, with less guess work:
var data = ...;
var open = data.Substring(0, 4, removeFrom: ref data);
var inputLength = int.Parse(data.Substring(0, 1), removeFrom: ref data));
var input = data.Substring(0, inputLength, removeFrom: ref data);
Working Example
I've created a working example that you can test on .NET Fiddle; the complete code for it is:
using System;
public static class ExtensionMethods {
public static string Substring(this string input, int startingIndex, int length, ref string removeFrom) {
var substring = input.Substring(startingIndex, length);
removeFrom = removeFrom.Remove(startingIndex, length);
return substring;
}
}
public class Program {
public static void Main() {
var data = "alja5nerjvnalskjnbaeviunreklvnaslidhfvbaelkjnrfvliasndve";
Console.WriteLine(data);
var open = data.Substring(0, 4, removeFrom: ref data);
var inputLength = int.Parse(data.Substring(0, 1, removeFrom: ref data));
var input = data.Substring(0, inputLength, removeFrom: ref data);
Console.WriteLine(open);
Console.WriteLine(inputLength);
Console.WriteLine(input);
Console.WriteLine(data);
}
}
The expected output of which is:
alja5nerjvnalskjnbaeviunreklvnaslidhfvbaelkjnrfvliasndve
alja
5
nerjv
nalskjnbaeviunreklvnaslidhfvbaelkjnrfvliasndve
Notes
I have no interest in discussing the following:
- The use of
Parse
overTryParse
.- I don't care if the proof of concept blows up, I use
TryParse
where necessary.
- I don't care if the proof of concept blows up, I use
- The use of magic numbers in the second and final examples.
- I will actually have constants to represent things such as
openLength
andexpectedInputLength
.
- I will actually have constants to represent things such as
- The lack of validation for
removeFrom
in the extension method.- I want this to blow up if the implementation doesn't check the value prior.
- Stylistic issues such as:
- Brace placement.
- Indentation.
I'd like the community's review of this extension method. My biggest concern in particular is the name of the method not clearly articulating what's going on, even with the named variable in the implementation (which would be a standards thing).
data.Substring(..., ref data)
looks really weird. I do understand the intent but passing the same parameter twice seems odd. Are you interested about alternative solution for this particular problem? \$\endgroup\$input
andremoveFrom
parameters. \$\endgroup\$