[C#] Adding Functionality to Existing Classes by Defining Extension Methods

C# has a feature called “Extension Methods” that allows you to add new methods to existing types (classes, structs, interfaces) without using inheritance or directly modifying the source code.

This allows you to implement utility functions for standard .NET classes (such as string or List<T>) or third-party libraries and behave as if those methods originally existed in the class.

In this article, I will introduce an implementation example that adds “Title Case conversion (capitalizing the first letter of words)” and “Base64 Encode/Decode” functionality to the string type.

目次

Rules for Defining Extension Methods

To define an extension method, you must meet the following three conditions:

  1. Define it inside a static class.
  2. The method itself must be a static method.
  3. Add the this keyword to the first argument to specify the type you want to extend.

Practical Code Example: Extending String Operations

The following code is an example of extending the string type with three methods.

  • ToTitleCase: Converts the string to title case (e.g., “john doe” → “John Doe”).
  • ToBase64: Encodes the string into Base64 format.
  • FromBase64: Decodes a Base64 format string back to the original string.
using System;
using System.Globalization;
using System.Text;
using System.Threading;

namespace CustomExtensions
{
    class Program
    {
        static void Main()
        {
            // --- 1. Usage example of Title Case conversion ---
            string authorName = "arthur conan doyle";
            
            // Can be called as if the method was added to the string type
            Console.WriteLine($"Original : {authorName}");
            Console.WriteLine($"Converted: {authorName.ToTitleCase()}");

            Console.WriteLine();

            // --- 2. Usage example of Base64 Encode/Decode ---
            string secretMessage = "API_Key_12345";
            
            // Encode
            string encoded = secretMessage.ToBase64();
            Console.WriteLine($"Base64   : {encoded}");

            // Decode
            string decoded = encoded.FromBase64();
            Console.WriteLine($"Decoded  : {decoded}");
        }
    }

    // Static class defining extension methods
    // The class name is arbitrary, but "TypeName + Extensions" is common.
    public static class StringExtensions
    {
        /// <summary>
        /// Converts string to Title Case (capitalizes the first letter of each word).
        /// </summary>
        public static string ToTitleCase(this string str)
        {
            if (string.IsNullOrEmpty(str)) return str;

            // Performs conversion using current culture information
            CultureInfo cultureInfo = Thread.CurrentThread.CurrentCulture;
            TextInfo textInfo = cultureInfo.TextInfo;

            return textInfo.ToTitleCase(str);
        }

        /// <summary>
        /// Encodes the string into Base64 format.
        /// </summary>
        /// <param name="str">Target string</param>
        /// <param name="encoding">Encoding (UTF-8 if not specified)</param>
        public static string ToBase64(this string str, Encoding encoding = null)
        {
            if (string.IsNullOrEmpty(str)) return string.Empty;

            // Default to UTF-8 (Assuming standard Web usage)
            var targetEncoding = encoding ?? Encoding.UTF8;
            var bytes = targetEncoding.GetBytes(str);
            
            return Convert.ToBase64String(bytes);
        }

        /// <summary>
        /// Decodes a Base64 format string.
        /// </summary>
        /// <param name="base64String">Base64 string</param>
        /// <param name="encoding">Encoding (UTF-8 if not specified)</param>
        public static string FromBase64(this string base64String, Encoding encoding = null)
        {
            if (string.IsNullOrEmpty(base64String)) return string.Empty;

            var targetEncoding = encoding ?? Encoding.UTF8;
            
            // Converts Base64 string back to byte array and then to string using specified encoding
            var bytes = Convert.FromBase64String(base64String);
            
            return targetEncoding.GetString(bytes);
        }
    }
}

Execution Result

Original : arthur conan doyle
Converted: Arthur Conan Doyle

Base64   : QVBJX0tleV8xMjM0NQ==
Decoded  : API_Key_12345

Technical Points and Precautions

1. Role of the this Keyword

The this string str in the first argument of the extension method tells the compiler “this method is called on an instance of type string.” Inside the method, you can access the caller instance (receiver) via the str variable.

2. Namespace Resolution

If the namespace containing the class where the extension methods are defined (in this case StringExtensions inside CustomExtensions) is not imported with using in the calling code, the extension methods will not be recognized. If they do not appear in IntelliSense, check for missing namespace imports.

3. Importance of Null Checks

With standard instance methods, calling a method on a null instance results in a NullReferenceException. However, since extension methods are essentially “syntactic sugar for static method calls,” execution can enter the method even if the receiver (the first argument) is null.

Therefore, it is recommended to perform a check like if (str == null) at the beginning of the extension method, or implement it so that it operates safely even with null.

Summary

Extension methods are very useful for improving code readability and building Fluent Interfaces. However, abusing them can make it difficult to determine where methods are defined, so it is recommended to limit their use to general-purpose utility functions.

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次