Castle Windsor如何注册同一泛型接口的多个泛型实现类
问题场景
现有如下泛型接口与实现定义:
public interface IFileHandler<TLocation,TRow> { ... } // 按RowTypeA定义的记录格式加载指定位置的文件 // 示例:RowTypeA类型的记录存储在匹配字符串'file_a.csv'的文件中 public class FileHandlerA<TLocation> : IFileHandler<TLocation, RowTypeA>{ ... } // 按RowTypeB定义的记录格式加载指定位置的文件 // 示例:RowTypeB类型的记录存储在匹配字符串'file_b.csv'的文件中 public class FileHandlerB<TLocation> : IFileHandler<TLocation, RowTypeB>{ ... } public class MyCode { ... public void MyMethod() { // 期望的解析效果 var fh1 = container.Resolve<IFileHandler<Location1, RowTypeA>>(); // 得到FileHandlerA<Location1>实例 var fh2 = container.Resolve<IFileHandler<Location2, RowTypeA>>(); // 得到FileHandlerA<Location2>实例 var fh3 = container.Resolve<IFileHandler<Location1, RowTypeB>>(); // 得到FileHandlerB<Location1>实例 } ... }
已尝试的注册方案
你之前尝试的两种注册思路方向都是正确的,只需要做少量调整即可生效:
// 扫描注册的写法存在语法缺漏 Classes .FromAssembly(thisAssembly) .BasedOn(typeof(IFileHandler<,>) // 缺了右括号 .WithServiceAllInterfaces(); // 开放泛型注册不知道怎么传实现类 Component .For<IFileHandler<,>>() .ImplementedBy<???>
Castle Windsor 正确注册方案
因为你的FileHandlerA<>/FileHandlerB<>属于半封闭泛型实现(已经固定了TRow泛型参数,仅保留TLocation作为开放参数),Castle Windsor原生支持这类泛型的自动匹配解析,两种注册方式调整后如下:
方案1:显式注册开放泛型实现
直接逐个注册对应行类型的半开放泛型实现即可,Windsor会在解析时自动填充TLocation参数:
container.Register( // 注册RowTypeA对应的处理器 Component.For(typeof(IFileHandler<,>)) .ImplementedBy(typeof(FileHandlerA<>)) .LifestyleTransient(), // 注册RowTypeB对应的处理器 Component.For(typeof(IFileHandler<,>)) .ImplementedBy(typeof(FileHandlerB<>)) .LifestyleTransient() );
方案2:修正后的程序集扫描注册
补全语法,并且指定用基接口作为服务暴露即可:
container.Register( Classes.FromAssembly(thisAssembly) .BasedOn(typeof(IFileHandler<,>)) // 补全右括号 .WithService.Base() // 只绑定IFileHandler<,>接口,比WithServiceAllInterfaces更精准 .LifestyleTransient() );
更优的设计方案
如果后续行类型会持续新增,每次新增RowType都要加对应的FileHandlerX实现会产生大量重复代码,可以把行类型和文件的匹配规则抽离,用统一的泛型实现:
- 先给行类型加匹配规则特性
[AttributeUsage(AttributeTargets.Class)] public class FilePatternAttribute : Attribute { public string Pattern { get; } public FilePatternAttribute(string pattern) => Pattern = pattern; } [FilePattern("file_a.csv")] public class RowTypeA { } [FilePattern("file_b.csv")] public class RowTypeB { }
- 实现通用泛型处理器
public class FileHandler<TLocation, TRow> : IFileHandler<TLocation, TRow> { public FileHandler() { // 从行类型特性中自动读取匹配规则 var filePattern = typeof(TRow).GetCustomAttribute<FilePatternAttribute>()?.Pattern; // 原有加载逻辑 } }
- 仅需注册一次开放泛型即可
container.Register( Component.For(typeof(IFileHandler<,>)) .ImplementedBy(typeof(FileHandler<,>)) .LifestyleTransient() );
后续新增行类型只需定义RowType类加FilePattern特性即可,不需要新增处理器实现,扩展性更强。
内容的提问来源于stack exchange,提问作者Denis
相关产品推荐
相关产品推荐

