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

C#运行时动态选择类:多客户架构实现方案咨询

解决方案:基于登录信息动态调用客户专属类

一、现有代码的核心问题

你当前的代码存在几个关键错误,导致无法正常实现动态调用:

  • 工厂类的类型扫描逻辑错误:只查找继承SomeBase的类,但CustomerA/CustomerB实现的是ICommon接口,工厂无法找到这两个类型
  • Service类的switch分支重复:两个case都写了"CustomerB",第一个分支应该对应"CustomerA"
  • Program类错误引用不存在的Service1,实际应该用Service
  • 使用dynamic会丢失编译时类型检查,容易引发运行时错误

二、修正后的完整代码

1. 接口定义(修正方法名拼写错误)

namespace FactoryPattern
{
    public interface ICommon
    {
        string GetCustomerName();
    }
}

2. 客户专属实现类

namespace FactoryPattern
{
    class CustomerA : ICommon
    {
        public string GetCustomerName()
        {
            return "i am CustomerA";
        }
    }

    class CustomerB : ICommon
    {
        public string GetCustomerName()
        {
            return "i am CustomerB";
        }
    }
}

3. 修正后的工厂类(扫描实现ICommon的类)

namespace FactoryPattern
{
    public sealed class CustomerFactory
    {
        private static readonly Dictionary<string, Type> TypeLookup;

        static CustomerFactory()
        {
            // 扫描当前程序集中所有实现ICommon接口的非抽象类
            TypeLookup = typeof(CustomerFactory).Assembly.GetTypes()
                .Where(t => t.IsClass && !t.IsAbstract && typeof(ICommon).IsAssignableFrom(t))
                .ToDictionary(t => t.Name, t => t, StringComparer.OrdinalIgnoreCase);
        }

        // 返回ICommon接口,实现强类型约束
        public ICommon Create(string customerClassName)
        {
            if (TypeLookup.TryGetValue(customerClassName, out var type))
            {
                return (ICommon)Activator.CreateInstance(type);
            }
            throw new ArgumentException($"找不到客户专属类:{customerClassName}");
        }
    }
}

4. 修正后的Service类(去掉dynamic,简化逻辑)

namespace FactoryPattern
{
    internal class Service
    {
        private readonly ICommon _customerInstance;

        public Service(string account)
        {
            var factory = new CustomerFactory();
            // 如果登录账号和类名一致,直接传入创建实例
            _customerInstance = factory.Create(account);

            // 如果账号和类名不匹配,可添加映射逻辑
            // string className = account switch
            // {
            //     "A_Account" => "CustomerA",
            //     "B_Account" => "CustomerB",
            //     _ => throw new ArgumentException("无效客户账号")
            // };
            // _customerInstance = factory.Create(className);
        }

        public string GetCustomerName()
        {
            return _customerInstance.GetCustomerName();
        }
    }
}

5. 修正后的程序入口

namespace FactoryPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            Service serviceA = new Service("CustomerA");
            Console.WriteLine(serviceA.GetCustomerName()); // 输出:i am CustomerA

            Service serviceB = new Service("CustomerB");
            Console.WriteLine(serviceB.GetCustomerName()); // 输出:i am CustomerB
        }
    }
}

三、后续优化建议

  • 配置化映射:如果登录账号和类名不一致,将映射关系放到配置文件(如appsettings.json),新增客户时无需修改代码
  • 依赖注入:把CustomerFactory注入到Service中,代替内部实例化,提升代码可测试性
  • 实例缓存:如果客户类是无状态的,缓存已创建的实例,避免重复反射实例化的性能开销
  • 连接字符串集成:在客户类构造函数中传入对应Schema的连接字符串,实现数据库访问的隔离

内容的提问来源于stack exchange,提问作者Pie_Gee

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 14:56:09