返回文章列表文章索引阅读全文
STARBLOG / 阅读手记
C#

Can C# Extension Methods Only Use this? C# 14's New Syntax Takes Extension Methods to a Whole New Level

.NET 10's extension method syntactic sugar? Oh, you define extensions with `extension` blocks, and they support properties and methods now—couldn't before, can now, how novel. Static extension members? A bit late, but adding static methods to `DateTime` can finally be elegant. Upgrade already, or how else are you going to enjoy these new toys?

曦远 (DealiAxy)约 15 分钟
目录7 个章节

Introduction

PS: Come on, AI programming is everywhere now—why is anyone still studying programming language syntax?

Just kidding, haha. For some simple and highly customized code, writing it by hand is still better. In the time it takes to talk to an AI, I could've already written the code 😄

Recently I've been writing some analysis scripts for StarBlog and needed extension methods to simplify the code. I recalled seeing in the .NET 10 update docs a while back that there's a new extension method syntax. I originally thought it would be like Kotlin, where you no longer need to write a static class—turns out you still do…

But the new syntax is still pretty nice to use.

PS: Even though I write the code myself, I don't have to read the docs anymore—just let AI summarize them 😄

I'll take this opportunity to document the new syntax.

From Static Methods to Extension Blocks

Traditional extension methods require repeating the this parameter on every method, and you can only extend methods. The new syntax uses the extension keyword to define a block, declaring the target type in one place.

The traditional way looks like this

public static class StringExtensions {
    // 每个方法都要写一遍 (this string str)
    public static bool IsValidEmail(this string str) => str.Contains("@");
    public static string ToTitleCase(this string str) => ...;
}

New syntax (C# 14 / .NET 10)

public static class MyExtensions {
    // 定义一个针对 string 的扩展块,str 是接收者名称
    extension(string str) {
        // 1. 扩展属性 (以前做不到)
        public bool IsValidEmail => str.Contains("@");

        // 2. 扩展方法 (不再需要写 static 和 this)
        public string ToTitleCase() => char.ToUpper(str[0]) + str.Substring(1);
    }
}

Member Types Supported by the New Syntax

This is the most powerful part of .NET 10—the range of what you can extend has been greatly expanded:

Member typeSupportedExample syntax
Instance methodsYespublic void M() => ...
Instance propertiesYespublic int Length => str.Length;
Static methodsYespublic static void Help() => ...
Static propertiesYespublic static string Default => "None";
Operator overloadsYespublic static bool operator +(string a, MyType b)
IndexersYespublic char this[int i] => str[i];

Static Extension Members

Previously we couldn't add static utility methods to an existing class (like DateTime or int). Now we can.

public static class DateTimeExtensions {
    // 注意:括号内只有类型,没有实例名称,表示静态扩展
    extension(DateTime) {
        public static DateTime Tomorrow => DateTime.Now.AddDays(1);
    }
}

// 使用时:
var nextDay = DateTime.Tomorrow; // 就像 DateTime 原生自带的一样

Generic Support

The new syntax's support for generics is very elegant, especially when working with collections (LINQ-style):

public static class EnumerableExtensions {
    extension<T>(IEnumerable<T> source) {
        // 扩展属性:判断集合是否为空
        public bool IsEmpty => !source.Any();
        
        // 扩展方法
        public void ForEach(Action<T> action) {
            foreach (var item in source) action(item);
        }
    }
}

Actual Code

Since I mentioned these are scripts written for StarBlog, I might as well share the actual code I used (padding the word count (not really))

It's actually an extension method that extracts the paragraph under a markdown second-level heading

public static class MyExtensions {
    extension(Post post) {
        public string GetSection(string title) {
            return ExtractSectionRegex(post.Content, title);
        }

        public Dictionary<string, string> GetSections(params string[] titles) {
            var dict = new Dictionary<string, string>();
            foreach (var title in titles) {
                dict.Add(title, post.GetSection(title));
            }

            return dict;
        }
    }

    private static string ExtractSectionRegex(string content, string title) {
        // 匹配目标标题开始,直到下一个标题或文档末尾
        string pattern = $@"##\s*{title}\s*([\s\S]*?)(?=\n##|$)";
        var match = Regex.Match(content, pattern);
        return match.Success ? match.Groups[1].Value.Trim() : string.Empty;
    }
}

This GetSections method can actually be simplified further with LINQ syntax

public Dictionary<string, string> GetSections(params string[] titles) {
    return titles.ToDictionary(title => title, title => post.GetSection(title));
}

Then simplify it again with a method group, and the final result is

public Dictionary<string, string> GetSections(params string[] titles) {
    return titles.ToDictionary(title => title, post.GetSection);
}

Now THAT's what you call elegant?! 🐸

Wrap-up

The new extension syntactic sugar is pretty sweet. As I see it, there are a few advantages:

  • More natural code: Extension properties make the API look more like a native part of the target type, rather than having to call a method with parentheses.
  • Logic in one place: Defining all related extensions in a single extension block makes the code structure clearer than methods scattered across a static class.
  • Zero breaking changes: The new syntax is fully compatible with the old this extension method syntax, so you can mix them as you like.

Note: These new features are only available if you have the .NET 10 SDK installed and set <LangVersion> to 14.0 or preview in your project file.

So hurry up and upgrade all your projects to .NET 10 😄

PS: This StarBlog project of mine has been upgraded all the way from .NET 6 to .NET 10—it's a project with a bit of history at this point 🤣

_EOF_

Can C# Extension Methods Only Use this? C# 14's New Syntax Takes Extension Methods to a Whole New Level

本文作者:
程序设计实验室
版权声明:
本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

相关文章

SharpIco:用纯C#打造零依赖的.ico图标生成器,支持.NET9与AOT编译

SharpIco 是一款纯 C# 实现的跨平台图标生成工具,支持 AOT 编译,无需外部依赖。它能将 PNG 图片分解为多尺寸(16x16至512x512)合成 ICO 图标,并支持图标结构分析。工具提供命令行界面,可通过 dotnet tool 一键安装,并已发布至 NuGet 和 Scoop。项目旨在简化图标生成与验证,追求轻量、纯粹、易集成的使用体验。

2025-05-26 · C# · 约 1 分钟

System.Text.Json使用中的几个常见问题

前言 以前.NetCore是不内置JSON库的,所以大家都用Newtonsoft的JSON库,而且也确实挺好用的,不过既然官方出了标准库,那更方便更值得我们多用用,至少不用每次都nuget安装Newtonsoft.Json库了。 不过日常开发使用中会有一些问题,本文记录一下解决方法,欢迎交流~ ~~(文章末尾包含小彩蛋)~~ 字符编码问题 默认的 System.Text.Json 序列化的时候会把

2022-05-27 · C# · 约 1 分钟

C#学习(一)委托的概念和使用

前言 C#学习系列是根据我以前的笔记整理出来复习,顺便发一下文章做个记录。 先引用一个介绍: C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。 委托(Delegate)特别用于实现事件和回调方法。所有的委托(Delegate)都派生自 System.Delegate 类。 根据使用其他

2021-12-18 · C# · 约 1 分钟

讨论

共 0 条

良言一句三冬暖,恶语伤人六月寒。

加载评论中…