You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 17:15:58