zigs leads a community discussion exploring the most effective helper methods and C# extension patterns, sharing useful code snippets that simplify .NET development workflows.

Developer Discussion: Most Impactful Low-Effort C# Helper Methods

Author: zigs

Overview

This discussion centers on the highest impact, lowest effort helper methods C# developers have written to improve daily coding experience. From enhancing LINQ pipelines to streamlining null checks and manipulating dates, practitioners share specific examples, code snippets, and explanations for why these utilities boost productivity and readability.


LINQ-Friendly String Joining

Example:

public static class IEnumerableExtensions {
    public static string StringJoin<T>(this IEnumerable<T> source, string separator) =>
        string.Join(separator, source.Select(item => item?.ToString()));

    public static string StringJoin<T>(this IEnumerable<T> source, char separator) =>
        string.Join(separator, source.Select(item => item?.ToString()));
}

Why: Enables LINQ-style chaining, so instead of mixing nested calls like this:

string.Join(", ", myItems.Select(item => $"{item.Id} ({item.Name})"))

…you write:

myItems.Select(item => $"{item.Id} ({item.Name})").StringJoin(", ")

This keeps the data-flow pipeline consistent and easier to read.


SQL-Style Inclusion Check (IsIn)

Example:

public static bool IsIn<T>(this T obj, params T[] values) {
    foreach (T val in values) if (val.Equals(obj)) return true;
    return false;
}

public static bool IsIn<T>(this T obj, IComparer comparer, params T[] values) {
    foreach (T val in values) if (comparer.Compare(obj, val) == 0) return true;
    return false;
}

Why: Allows writing checks like foo.IsIn(1, 2, 3) instead of repeating equality or using more verbose syntax.


Functional Filtering (Choose)

Inspired by F#’s choose, this helps filter and project simultaneously:

public static IEnumerable<U> Choose<T, U>(this IEnumerable<T> source, Func<T, U?> selector) where U : struct {
    foreach (var elem in source) {
        var projection = selector(elem);
        if (projection.HasValue) yield return projection.Value;
    }
}

public static IEnumerable<U> Choose<T, U>(this IEnumerable<T> source, Func<T, U?> selector) {
    foreach (var elem in source) {
        var projection = selector(elem);
        if (projection != null) yield return projection;
    }
}

Why: Streamlines the pattern of projecting and filtering out nulls in one LINQ-style operation, essentially equivalent to .Select().Where(...).


Async/Task Helpers

Quickly await and unpack multiple tasks:

public static async Task<(T0, T1, T2)> WhenAll<T0, T1, T2>(Task<T0> t0, Task<T1> t1, Task<T2> t2) {
    await Task.WhenAll(t0, t1, t2);
    return (t0.Result, t1.Result, t2.Result);
}

Usage:

var (result1, result2, result3) = await Common.TaskHelper.WhenAll(
    DuStuff1Async(),
    DuStuff2Async(),
    DuStuff3Async());

String Null/Empty Checks

Helpers for readability and succinctness in predicates:

public static bool IsNotEmpty(this string text) => !string.IsNullOrWhiteSpace(text);
public static bool IsNullOrWhiteSpace(this string str) => string.IsNullOrWhiteSpace(str);
public static bool IsNotNullOrWhiteSpace(this string str) => !IsNullOrWhiteSpace(str);
public static bool IsNullOrEmpty(this string str) => string.IsNullOrEmpty(str);
public static bool IsNotNullOrEmpty(this string str) => !IsNullOrEmpty(str);

Use as .Where(IsNotEmpty) and similar for clarity.


Miscellaneous String and DateTime Helpers

Examples include:

  • ContainsOnlyCharactersIn, RemoveCharactersNotIn for advanced string filtering
  • CamelCaseToSpaced, PrettyName for improving name formatting
  • Enum and value validation
  • Date math helpers: EndOfPreviousMonth, EndOfMonth, FirstOfMonth, etc.

DateTime With Suffix: Adds “st”, “nd”, “rd”, “th” to day:

public static string ToStringWithSuffix(this DateTime dateTime, string format, string suffixPlaceHolder = "$") {
    if(format.LastIndexOf("d", StringComparison.Ordinal) == -1 || format.Count(x => x == 'd') > 2) {
        return dateTime.ToString(format);
    }
    string suffix;
    switch(dateTime.Day) {
        case 1: case 21: case 31: suffix = "st"; break;
        case 2: case 22: suffix = "nd"; break;
        case 3: case 23: suffix = "rd"; break;
        default: suffix = "th"; break;
    }
    var formatWithSuffix = format.Insert(format.LastIndexOf("d", StringComparison.InvariantCultureIgnoreCase) + 1, suffixPlaceHolder);
    var date = dateTime.ToString(formatWithSuffix);
    return date.Replace(suffixPlaceHolder, suffix);
}

Conclusion

The thread underscores the power of simple helpers in amplifying code clarity and reducing boilerplate in .NET development. While each helper seems trivial in isolation, collectively they enable more expressive and maintainable codebases.

This post appeared first on “Reddit CSharp”. Read the entire article here