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

C#替换预处理器指令实现单安装包适配双许可模式方案咨询

单安装包动态许可切换实现方案

1 预处理器逻辑改写为运行时判断的C#代码

核心思路是把编译期分支改为运行时基于许可证文件的判断,步骤如下:

  • 第一步:定义许可类型枚举,封装DAT许可证读取、校验逻辑
  • 第二步:删除原#if TRAIL/#elif LICENSED预处理器指令,替换为运行时的许可类型判断
  • 第三步:所有和许可相关的分支代码都保留编译到程序集,运行时根据许可状态动态执行

示例代码:

using System.IO;

// 许可类型枚举
public enum LicenseType
{
    Trial,
    Licensed,
    Invalid
}

// 许可证工具类,负责读取解析DAT格式许可
public static class LicenseHelper
{
    // 替换为实际的DAT许可证文件路径
    private const string LicenseFilePath = "license.dat";

    public static LicenseType GetCurrentLicenseType()
    {
        if (!File.Exists(LicenseFilePath))
            return LicenseType.Trial;

        try
        {
            // 这里替换为实际的DAT文件读取、解密、校验逻辑
            var content = File.ReadAllText(LicenseFilePath).Trim();
            // 示例判断:DAT文件包含有效授权标记则返回正式许可,否则返回试用
            return content.Contains("VALID_LICENSE_SIGN") ? LicenseType.Licensed : LicenseType.Trial;
        }
        catch
        {
            return LicenseType.Trial;
        }
    }

    // 监听许可文件变更的方法,用于热切换场景
    public static void WatchLicenseChange(Action onChange)
    {
        var watcher = new FileSystemWatcher(Path.GetDirectoryName(LicenseFilePath), Path.GetFileName(LicenseFilePath))
        {
            NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.Size
        };
        watcher.Changed += (s, e) => onChange();
        watcher.Created += (s, e) => onChange();
        watcher.Deleted += (s, e) => onChange();
        watcher.EnableRaisingEvents = true;
    }
}

public static class SomeStaticClass
{
    public static string PropertyId { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        // 初始化前先读取当前许可类型
        var currentLicense = LicenseHelper.GetCurrentLicenseType();
        
        // 替换原来的预处理器分支
        if (currentLicense == LicenseType.Trial)
        {
            SomeStaticClass.PropertyId = "10023";
            // 试用版相关初始化代码
        }
        else if (currentLicense == LicenseType.Licensed)
        {
            SomeStaticClass.PropertyId = "10024";
            // 正式版相关初始化代码
        }

        // 注册对应许可版本的事件
        // 创建对应许可版本的会话
        // 后续业务逻辑...

        // 监听许可文件变更,触发重载流程
        LicenseHelper.WatchLicenseChange(() =>
        {
            // 这里触发重载逻辑,推荐用进程重启方案,避免静态资源残留问题
            RestartApplication();
        });
    }

    // 应用重启方法,重新走Main初始化流程
    static void RestartApplication()
    {
        // 释放当前进程占用的所有资源、会话、引擎实例
        // 这里替换为实际的资源释放逻辑,比如关闭数据库连接、销毁引擎实例等
        var currentProcessPath = Environment.ProcessPath;
        if (currentProcessPath != null)
        {
            System.Diagnostics.Process.Start(currentProcessPath);
            Environment.Exit(0);
        }
    }
}

2 许可升降级后的逻辑切换方案

  • 进程自动重启方案(优先推荐):用户更新许可文件后,程序监听到变更自动重启,重新执行Main方法的初始化逻辑,完全重置所有会话、异常处理器、引擎配置,没有静态变量残留的风险,实现成本最低,稳定性最高。
  • 运行时热重载方案:如果业务不允许重启进程,需要把所有许可相关的依赖都封装为非静态的服务实例,许可变更时先销毁旧的服务实例,再根据新的许可类型重新初始化所有实例、注册事件、创建会话,需要额外处理静态变量重置、内存泄漏、未完成请求的兼容问题。
  • 下次启动生效方案:许可变更后给用户弹窗提示,下次启动程序时自动切换许可模式,不需要额外监听逻辑,实现最简单,缺点是切换不会立即生效。

3 许可变更后重载Main流程的注意事项

  1. 静态变量需要显式重置:所有和许可相关的静态属性(比如示例中的SomeStaticClass.PropertyId)在重载前需要恢复默认值,避免旧值残留。
  2. 资源必须完全释放:原有会话、引擎、文件句柄、网络连接等资源要在重载前正确释放,避免出现资源占用冲突。
  3. 用户数据临时保存:如果采用重启方案,需要在重启前临时保存用户未完成的操作数据,重启后自动恢复,避免用户数据丢失。

内容的提问来源于stack exchange,提问作者Gani.one

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 13:27:03