使用TinyIoc注册与解析Func<>的问题
解决TinyIoc中多个Func注册的歧义问题
我之前也踩过TinyIoc处理多委托注册的坑,咱们来拆解下这个问题:
首先明确:TinyIoc支持命名委托注册,但方式要正确
你遇到的歧义问题,本质是因为TinyIoc对委托的默认解析逻辑是取最后注册的那个实现,而命名注册的委托需要显式指定才能被正确注入,不能依赖自动匹配。
举个正确的注册&解析示例:
1. 注册命名的Func
var container = new TinyIoCContainer(); // 注册第一个命名委托 container.Register<Func<string>>(() => () => "来自第一个委托的内容", "FirstStringFunc"); // 注册第二个命名委托 container.Register<Func<string>>(() => () => "来自第二个委托的内容", "SecondStringFunc");
2. 显式指定依赖的委托名称来注册服务
假设你的依赖类型是这样的:
public class DependentService { private readonly Func<string> _stringGetter; public DependentService(Func<string> stringGetter) { _stringGetter = stringGetter; } public string GetResult() => _stringGetter(); }
如果直接用container.Resolve<DependentService>(),TinyIoc会自动注入最后注册的SecondStringFunc。要注入指定的委托,你需要在注册DependentService时,显式解析对应名称的委托:
// 注册依赖第一个委托的服务实例 container.Register<DependentService>(c => new DependentService(c.Resolve<Func<string>>("FirstStringFunc"))); // 或者如果需要多个不同实例,可以给服务也加名称 container.Register<DependentService>(c => new DependentService(c.Resolve<Func<string>>("SecondStringFunc")), "ServiceUsingSecondFunc");
这样解析时指定服务名称,就能得到注入了对应委托的实例:
var service1 = container.Resolve<DependentService>(); Console.WriteLine(service1.GetResult()); // 输出:来自第一个委托的内容 var service2 = container.Resolve<DependentService>("ServiceUsingSecondFunc"); Console.WriteLine(service2.GetResult()); // 输出:来自第二个委托的内容
更推荐的方案:用策略模式包装委托
虽然TinyIoc支持命名委托注册,但这种方式可读性较差,而且后期维护时容易搞混哪个委托对应哪个服务。更优雅的方式是把委托逻辑包装成带标识的接口实现(也就是策略模式):
1. 定义策略接口
public interface IStringProvider { string GetString(); }
2. 实现不同的策略类
public class FirstStringProvider : IStringProvider { public string GetString() => "来自第一个策略的内容"; } public class SecondStringProvider : IStringProvider { public string GetString() => "来自第二个策略的内容"; }
3. 注册与使用
// 注册不同的策略实现 container.Register<IStringProvider, FirstStringProvider>("FirstProvider"); container.Register<IStringProvider, SecondStringProvider>("SecondProvider"); // 注册依赖策略的服务 container.Register<DependentService>(c => new DependentService(() => c.Resolve<IStringProvider>("FirstProvider").GetString()));
这种方式的优势在于:
- 逻辑更清晰,每个策略有明确的类和职责
- 依赖关系更直观,后期排查问题或扩展新逻辑时更方便
- 避免了委托类型本身无标识导致的歧义问题
总结
- TinyIoc支持命名的委托注册,但需要在依赖服务的注册阶段显式指定要解析的委托名称,不能依赖自动注入的默认逻辑
- 从可维护性角度出发,更推荐用策略模式将委托包装为接口实现,这是解决此类依赖歧义问题的更优解
内容的提问来源于stack exchange,提问作者HankTheTank
相关产品推荐
相关产品推荐

