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
相关产品推荐
相关产品推荐

