使用C#中的lambdas进行流畅的接口配置
本文关键字:接口 配置 中的 lambdas 使用 | 更新日期: 2023-09-27 18:21:52
许多开源项目使用Configuration类和lambda来澄清复杂对象的配置。以公共交通为例。一个简单的配置就是这样。
Bus.Initialize(sbc =>
{
sbc.UseMsmq();
sbc.VerifyMsmqConfiguration();
sbc.VerifyMsDtcConfiguration();
sbc.UseMulticastSubscriptionClient();
sbc.ReceiveFrom("msmq://localhost/test");
});
当您将鼠标悬停在Visual Studio中的Initialize
上时,它会显示方法调用的参数为Action<ServiceBusConfigurator>
。我想知道是否有人可以展示一个如何在类中使用此模式的简单示例。我甚至不知道该怎么称呼这种模式,而且我的"GoogleFu"还不起作用。在这种特殊的情况下,我意识到该方法是在单例模式上操作的。但我同意将它作为类上的实例方法。
Action<ServiceBusConfigurator>
是一种方法,它接受ServiceBusConfigurator
类型的单个参数,对该实例执行"操作",并且不返回任何内容(void
)。
.NET BCL(从3.5开始)具有预定义的通用委托签名:Action<T>
、Action<T1, T2>
(等)用于不返回值的方法,Func<Tresult>
、Func<T, Tresult>
(等)适用于接受零个或多个参数并返回类型为Tresult
的单个结果实例的方法。
当您创建一个接受委托的方法时,您允许方法的调用方传递的不仅仅是数据参数——您的方法实际上将部分责任委托给了外部代码。在您的情况下,Bus.Initialize
创建ServiceBusConfigurator
(sbc
)的实例,然后使用sbc
实例作为参数调用指定的操作。
这基本上允许您的方法控制配置类实例的生存期。由调用者填写详细信息,但实际实例由您的类提供:
// this is not actual mass transit source code
public class BusCreator
{
public static IBus Initialize(Action<IConfiguration> action)
{
// create the config instance here
IConfiguration config = CreateDefaultConfig();
// let callers modify it
action(config);
// use the final version to build the result
return config.Build()
}
}
这样做的好处是,您构建的实例(在本例中为假想的IBus
)无法进一步修改。配置实例只会很快创建,传递给外部方法,然后用于创建一个不可变的最终对象:
IBus result = BusCreator.Configure(cfg => cfg.BusType = BusType.MSMQ);
在上面的行中需要注意两件事:
匿名方法内部的代码封装在传递给该方法的委托中。直到
Configure
方法实际调用它,它才会被执行cfg
参数由Configure
方法创建并传递给lambda。方法返回后,该对象不再存在(或者被包裹在生成的对象中)。
为了补充其他人的说法,这是进入流畅界面的"入口点"。使用Action回调来实现这一点的方法是一种很好的隔离fluent接口的方法,同时具有很强的可扩展性。
这类似于工作单元模式,它通常与事务和持久性场景相关,但似乎适合您的示例。
以下引文取自马丁·福勒对模式的定义:
工作单元跟踪您在可能影响数据库的业务事务中所做的一切。完成后,它会计算出由于您的工作而需要更改数据库的所有操作。
如果您更改初始化的业务事务和配置中的database,您可以更好地了解发生了什么。此外,将操作(在这种情况下为委托)视为原子操作:要么完全应用新配置,要么保持当前配置不变。
如前所述,动作本身并没有明确触及Bus
。即使不知道所涉及类的细节,我们也可以猜测这种交互是如何发生的:
ServiceBusConfigurator
可以在动作被调用之后、在Initializa()
方法返回之前(最有可能)被读取Bus
可能实现/扩展ServiceBusConfigurator
,使得Initialize()
可以传递this
作为被调用动作的参数(可能性较小)Bus
可能是静态的,并且对ServiceBusConfigurator
可见,这反过来又可以在调用ReceiveFrom()
时更改Bus
的配置属性(非常复杂,我希望非常不可能)
这些是我现在突然想到的一些策略。可能会有许多其他建议!