考虑以下代码:
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语句。
对我来说(尽管这个主题是新的),这似乎是一个漏洞的抽象。我们不得不在代码中添加方法调用,只是为了实现处理内容的方式。
有人可以帮助我理解这一点,并确认我是对还是错。
由于
答案 0 :(得分:5)
是的,当您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);
}
}
}
答案 1 :(得分:1)
您应该在调用代码中处理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<ICustomerCreditService>();
var myClass = new MyClass(service);
myClass.DoSomething();
}
kernel.BeginBlock()
会创建一个激活块。它确保在块结束时处理已解析的实例。
答案 2 :(得分:1)
你应该调用ICustomerCreditService
已经实例化的MyClass
的Dispose,因为ICustomerCreditService
现在不知道{{1}}的生命周期。
答案 3 :(得分:1)
从第一个实现开始,我将尝试向类添加一个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);
}
}
}
答案 4 :(得分:0)
是的,确实如此。但这是一个必要的邪恶。 IDisposable
接口的存在是一个漏洞抽象。漏洞抽象只是编程的日常事实。尽可能避免使用它们,但不要担心 - 无论如何它们无处不在。