You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

关于通过Reflection访问C# 14静态扩展方法与扩展属性的技术问询

关于通过Reflection访问C# 14静态扩展方法与扩展属性的技术问询

嘿,这个问题我刚好在尝鲜C#14的时候踩过坑!确实目前官方文档这块讲得不够细,我来给你捋清楚怎么用反射搞定这些扩展成员:

先搞懂编译后的本质

C#14的extension块其实是个语法糖——编译器不会保留这个块本身的任何信息,里面定义的所有成员都会被提升到所在的静态类中,变成带特殊标记的静态成员。核心标记就是System.Runtime.CompilerServices.ExtensionAttribute,所有扩展方法、扩展属性的访问器都会带上这个特性。

一、反射访问C#14扩展方法

就拿你给出的WordCount扩展方法举例,编译后它会变成MyExtensions类里的静态方法,并且带有ExtensionAttribute。你可以这么找到并调用它:

using System.Reflection;
using System.Runtime.CompilerServices;

// 筛选出带ExtensionAttribute的静态方法
var wordCountMethod = typeof(MyExtensions)
    .GetMethods(BindingFlags.Static | BindingFlags.Public)
    .First(m => 
        m.Name == "WordCount" && 
        m.GetCustomAttribute<ExtensionAttribute>() != null);

// 调用扩展方法:第一个参数必须是扩展的目标对象(比如string实例)
var result = wordCountMethod.Invoke(null, new object[] { "Hello! How are you today?" });
Console.WriteLine(result); // 输出 5

二、反射识别并访问扩展属性

你提到看到了get_WordCount方法,这说明你定义的是扩展属性(如果是方法的话编译后不会带get_前缀)。这里要注意:编译器不会为扩展属性生成真正的PropertyInfo,只会生成带ExtensionAttribute且标记了IsSpecialName=trueget_XXX/set_XXX静态方法。

你可以通过这两个特征来区分普通静态方法和扩展属性的访问器,而不用只靠命名约定:

var myExtensionsType = typeof(MyExtensions);

// 拿到所有带ExtensionAttribute的静态成员
var extensionMembers = myExtensionsType
    .GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
    .Where(m => m.GetCustomAttribute<ExtensionAttribute>() != null);

// 筛选出扩展属性的get访问器
var extensionPropertyGetters = extensionMembers
    .Where(m => 
        m.IsSpecialName && // 编译器给属性访问器加的特殊标记
        m.Name.StartsWith("get_"))
    .Select(m => new
    {
        PropertyName = m.Name.Substring(4), // 去掉get_前缀得到属性名
        GetMethod = m,
        TargetType = m.GetParameters()[0].ParameterType // 扩展的目标类型,比如string
    });

// 调用WordCount扩展属性的get方法
var wordCountGetter = extensionPropertyGetters.First(p => p.PropertyName == "WordCount");
var count = wordCountGetter.GetMethod.Invoke(null, new object[] { "This is a test sentence." });
Console.WriteLine(count); // 输出 5

关键总结

  • 别找extension块本身:编译后它就消失了,所有成员都直接属于外层的静态类
  • ExtensionAttribute识别扩展成员:这是最可靠的标记,比命名约定靠谱
  • 扩展属性没有原生PropertyInfo:必须通过对应的get_/set_方法来访问,记得检查IsSpecialName来确认是属性访问器而非普通方法

火山引擎 最新活动