如果实现接口调用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接口的存在是一个漏洞的抽象。 漏洞抽象只是编程的日常事实。 尽可能避免使用它们,但是当你不能的时候不要担心 – 无论如何它们无处不在。