For the question, `The class System.String is sealed and therefore you cannot use it for overriding or inheritance?’ There is a Yes and a No answer. Yes! you can extend existing types by using extension methods. Extension methods, naturally, can only access the public interface of the type or you can write your own extension method for the string operations.
In this blog, I am going to show you how to create new operations to existing string objects. The following code explains typical string operations that we come across in our day-t0-day coding, to get the Left , Right, Shorten operations. It does look very technical, i.e. the string manipulations, the condition checks. However, this is the solution from a technical point of view.
using System;
namespace My.Extensions
{
public static class StringExtensions
{
public static string Left(this string s, int count) {
if(count > s.Length) {
return s;
}
return s.Substring(0, count);
}
public static string Right(this string s, int count) {
if(s.Length <= count) {
return s;
}
return s.Substring(s.Length – count, count);
}
public static string Shorten(this string s, int count) {
if(s.Length < count) {
return String.Empty;
}
return s.Substring(0, s.Length – count);
}
}
}
There is a way to implement that functionality in a descriptive way which makes it look more aesthetic. The key is to understand a string as a sequence of characters. Let’s try to rewrite the extension methods using LINQ:
The code is shorter; it looks more precise. The core part of the methods is extremely descriptive. The methods meet respective purpose by taking or skipping a certain number of characters of the input string.
using System.Collections.Generic; using System.Linq;
namespace My.Extensions
{
public static class StringExtensions
{
public static string Left(this string characters, int number) {
return characters.Take(number).AsString();
}
public static string Right(this string characters, int number) {
return characters.Skip(characters.Length – number).AsString();
}
public static string Shorten(this string characters, int number) {
return characters.Take(characters.Length – number).AsString();
}
}
public static class EnumerableExtensions
{
public static string AsString(this IEnumerable<char> characters) {
return new string(characters.ToArray());
}
}
}
Unit testing the original implementation as well as the one developed here:
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace My.Extensions.Tests
{
[TestClass]
public class MyExtensionsSpecifications
{
private const string Abcdefghij = “abcdefghij”;
[TestMethod]
public void The_first_5_characters_of_abcdefghij_are_abcde() {
Assert.AreEqual(“abcde”, Abcdefghij.Left(5));
}
[TestMethod]
public void The_first_50_characters_of_abcdefghij_are_abcdefghij() {
Assert.AreEqual(Abcdefghij, Abcdefghij.Left(50));
}
[TestMethod]
public void The_last_3_characters_of_abcdefghij_are_hij() {
Assert.AreEqual(“hij”, Abcdefghij.Right(3));
}
[TestMethod]
public void The_last_20_characters_of_abcdefghij_are_abcdefghij() {
Assert.AreEqual(Abcdefghij, Abcdefghij.Right(20));
}
[TestMethod]
public void abcdefghij_shortened_by_4_characters_is_abcdef() {
Assert.AreEqual(“abcdef”, Abcdefghij.Shorten(4));
}
[TestMethod]
public void abcdefghij_shortened_by_12_characters_is_an_empty_string() {
Assert.AreEqual(string.Empty, Abcdefghij.Shorten(12));
}
}
}