.NET 8单文件发布后反射设置私有属性失败求助
问题:单文件发布后反射设置私有属性失败(Property set method not found)
这段代码在.NET 4.6.2、.NET 8的DEBUG模式下运行正常,但发布为单文件后调用SetupKeys时抛出**“Property set method not found”**异常,核心是通过反射给带私有set的静态属性赋值时找不到对应的set方法。
原代码
/// <summary> /// This gets called at startup. The point of this is to prevent us from /// making everything a const with [General.Yes = "General.Yes"]. Saves a step in /// development that was getting annoying. /// </summary> public static void SetupKeys() { var thisNamespace = typeof( TranslationKeys ).Namespace; var thisName = nameof( TranslationKeys ); var fullNameStart = string.Concat( thisNamespace, ".", thisName, "+" ); var classes = Assembly.GetExecutingAssembly() .GetTypes() .Where( t => t.IsClass && t.IsNested && t.FullName != null && t.FullName.StartsWith( fullNameStart ) ); foreach (var c in classes) { var className = c.Name; var props = c.GetProperties(); foreach (var p in props) { var propName = p.Name; p.SetValue(null, string.Concat(className, ".", propName), BindingFlags.NonPublic, ); } } } /// <summary> /// Things that we will use all over the place. /// </summary> public static class General { public static string Yes { get; private set; } = string.Empty; }
解决办法
1. 修正反射的BindingFlags参数
当前调用SetValue时仅传入BindingFlags.NonPublic,但静态属性需要同时指定BindingFlags.Static,且属性本身是public的,需补充BindingFlags.Public。同时获取属性时也要确保覆盖正确的范围:
public static void SetupKeys() { var thisNamespace = typeof(TranslationKeys).Namespace; var thisName = nameof(TranslationKeys); var fullNameStart = string.Concat(thisNamespace, ".", thisName, "+"); // 改用typeof获取程序集,避免单文件环境下执行程序集不一致问题 var classes = typeof(TranslationKeys).Assembly .GetTypes() .Where(t => t.IsClass && t.IsNested && t.FullName != null && t.FullName.StartsWith(fullNameStart)); foreach (var c in classes) { var className = c.Name; // 指定BindingFlags获取public静态属性 var props = c.GetProperties(BindingFlags.Public | BindingFlags.Static); foreach (var p in props) { var propName = p.Name; // 组合正确的BindingFlags:public静态属性 + 非公共set方法 p.SetValue(null, string.Concat(className, ".", propName), BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic, null, null, null); } } }
2. 禁用或配置单文件发布的裁剪优化
.NET 6+单文件发布默认启用代码裁剪(Trim),编译器会移除它认为未被直接调用的私有方法(包括属性的私有set)。可以通过两种方式处理:
- 全局禁用裁剪:在项目文件(.csproj)中添加配置,适合调试阶段:
<PropertyGroup> <PublishTrimmed>false</PublishTrimmed> </PropertyGroup> - 保留指定类型的私有set方法:使用
[DynamicDependency]特性告诉编译器不要裁剪相关方法,适合需要保留裁剪优化的场景:
如果需要批量处理using System.Diagnostics.CodeAnalysis; public static class General { [DynamicDependency(DynamicallyAccessedMemberTypes.PrivateSetters, typeof(string))] public static string Yes { get; private set; } = string.Empty; }TranslationKeys下的所有嵌套类属性,也可以在TranslationKeys类上添加特性:[DynamicDependency(DynamicallyAccessedMemberTypes.PrivateSetters, typeof(TranslationKeys.General))] public static class TranslationKeys { // 嵌套类定义... }
内容的提问来源于stack exchange,提问作者FoxScully
相关产品推荐
相关产品推荐

