如果实现接口调用Dispose,它是否是一个漏洞抽象
考虑以下代码:
public class MyClass() { public MyClass() { } public DoSomething() { using (var service = new CustomerCreditServiceClient()) { var creditLimit = service.GetCreditLimit( customer.Firstname, customer.Surname, customer.DateOfBirth); } } }
我们现在想重构它以松散地耦合它。 我们最终得到这个:
public class MyClass() { private readonly ICustomerCreditService service; public MyClass(ICustomerCreditService service) { this.service= service; } public DoSomething() { var creditLimit = service.GetCreditLimit( customer.Firstname, customer.Surname, customer.DateOfBirth); } }
看起来不错吧? 现在任何实现都可以使用该接口,一切都很好。
如果我现在说实现是一个WCF类并且重构之前的using语句是有原因的,那该怎么办? ie /关闭WCF连接。
所以现在我们的接口必须实现Dispose
方法调用,或者我们使用工厂接口来获取实现并在其周围放置一个using语句。
对我来说(尽管这个主题是新的),这似乎是一个漏洞的抽象。 我们不得不在我们的代码中添加方法调用,只是为了实现处理内容的方式。
有人可以帮助我理解这一点,并确认我是对还是错。
谢谢
是的,当您让ICustomerCreditService
实现IDisposable
时,它是一个漏洞抽象,因为您现在已经编写了ICustomerCreditService
并考虑了特定的实现。 此外,这向该接口的消费者传达它可以处置该服务,这可能是不正确的,特别是因为通常,资源应该由创建它的人(具有所有权)来处理。 当您将资源注入类(例如使用构造函数注入)时,不清楚是否给予使用者所有权。
所以一般来说,负责创建该资源的人应该处理它。
但是,在您的情况下,您可以通过实现ICustomerCreditServiceClient
的非一次性实现来简单地防止这种情况发生,该实现只是在同一方法调用中创建和配置WCF客户端。 这使一切变得更加容易:
public class WcfCustomerCreditServiceClient : ICustomerCreditServiceClient { public CreditLimit GetCreditLimit(Customer customer) { using (var service = new CustomerCreditServiceClient()) { return service.GetCreditLimit(customer.Firstname, customer.Surname, customer.DateOfBirth); } } }
您应该调用已经实例化的ICustomerCreditService
的Dispose,因为MyClass
现在不知道ICustomerCreditService
的生命周期。
从第一个实现开始,我将尝试向类添加一个getInterface-Request,以便实现可以保持或多或少相同。 然后它可以安全地调用Dispose
(实际上它只推迟了接口实现的创建,但仍然控制着它的生命周期):( c#-code not verified …)
public class MyClass() { public delegate ICustomerCreditService InterfaceGetter; private InterfceGetter getInterface; public MyClass(InterfaceGetter iget) { getInterface = iget; } public DoSomething() { using (var customerCreditService = getInterface()) { var creditLimit = customerCreditService.GetCreditLimit(customer.Firstname, customer.Surname, customer.DateOfBirth); } } }
您应该在调用代码中处理customerCreditService
的生命周期。 MyClass
应该如何知道调用者是否还需要该服务? 如果调用者负责清理其资源,那么MyClass
不需要是一次性的。
// calling method using (var service = new CustomerCreditServiceClient()) { var myClass = new MyClass(service); myClass.DoSomething(); }
更新:在评论中,OP提到了使用像Ninject这样的IoC。 然后代码可能如下所示:
IKernel kernel = ...; using (var block = kernel.BeginBlock()) { var service = block.Get(); var myClass = new MyClass(service); myClass.DoSomething(); }
kernel.BeginBlock()
创建一个激活块。 它确保在块结束时处理已解析的实例。
是的。 但这是一个必要的邪恶。 IDisposable
接口的存在是一个漏洞的抽象。 漏洞抽象只是编程的日常事实。 尽可能避免使用它们,但是当你不能的时候不要担心 – 无论如何它们无处不在。