C# 使用泛型和IDisposable指南

C# 使用泛型和IDisposable指南,c#,c#-4.0,C#,C# 4.0,在更有效的C#的第5项中,提出了以下内容: public class EngineDriver<T> where T : IEngine, new() { public void GetThingsDone() { T driver = new T(); using (driver as IDisposable) { driver.DoWork(); } } } 上面的代码不应该以完全相同的方式运行吗?事实上,原始代码不是很危

在更有效的C#的第5项中,提出了以下内容:

public class EngineDriver<T> where T : IEngine, new()
{
  public void GetThingsDone()
  {
    T driver = new T();
    using (driver as IDisposable)
    {
      driver.DoWork();
    }
  }
}

上面的代码不应该以完全相同的方式运行吗?事实上,原始代码不是很危险吗?因为驱动程序的生命周期超出了使用块,但是驱动程序在所述块的末尾被处理掉了吗?不,因为t不一定实现
IDisposable
(除非
IEngine
本身实现了它)-在这种情况下,第二个不会编译,而第一个会


关于驱动程序的范围,在第二个示例中的using块之后仍然可以访问它,这并不理想,尝试这样做通常会导致异常。理想情况下,您应该让
IEEngine
实现
IDisposable
,或者为
EngineDriver
添加一个无法实现它的附加约束。

使用可用的工具非常重要。编译建议的代码。我等几分钟


好了,你回来了。是的,您需要为IDisposable添加一个约束,以便using语句始终能够处理该对象。书中的代码是对该限制的一种破解,即使T没有实现IDisposable,它也能工作。使用(null){}是有效的。

只有当
IEngine
实现了
IDisposable
或者在
enginedDriver
上的类型参数中添加了额外的约束(对于
IDisposable
)时,您的第二个建议才会起作用。原始代码足够灵活,可以额外处理
IEngine
实现,这些实现也实现了
IDisposable

如果您确实担心在处理对象后使用该对象,您可以创建另一个作用域来包含该变量:

public class EngineDriver<T> where T : IEngine, new() {
  public void GetThingsDone() {
    {
      T driver = new T();
      using (driver as IDisposable) {
        driver.DoWork();
      }
    }
  }
}
公共类引擎驱动程序,其中T:IEngine,new(){
public void gethingsdone(){
{
T驱动器=新的T();
使用(驱动程序作为IDisposable){
driver.DoWork();
}
}
}
}
但对于这个例子来说,这是过分的;该方法的范围足够大。只有当您的方法更大时才有意义,例如:

public class EngineDriver<T> where T : IEngine, new() {
  public void GetThingsDone() {
    {
      T driver = new T();
      using (driver as IDisposable) {
        driver.DoWork();
      }
    }
    // do more stuff, can't access driver here ....
  }
}
公共类引擎驱动程序,其中T:IEngine,new(){
public void gethingsdone(){
{
T驱动器=新的T();
使用(驱动程序作为IDisposable){
driver.DoWork();
}
}
//执行更多操作,无法访问此处的驱动程序。。。。
}
}
但是,再一次,我只是展示一下这里可能的情况,我更愿意重构它,以便该块与其他代码隔离

您还可以拥有另一个作用域类:

public class DisposableWrapper<T> : IDisposable {
  public T Item { get; private set; }
  public DisposableWrapper(T item) { Item = item; }
  public void Dispose() {
    using (Item as IDisposable) { }
    Item = default(T);
  }
}

public static class DisposableWrapperExtensions {
  public static DisposableWrapper<T> AsDisposable<T>(this T item) {
    return new DisposableWrapper<T>(item);
  }
}

public class EngineDriver<T> where T : IEngine, new() {
  public void GetThingsDone() {
    using (var driver = new T().AsDisposable()) {
      driver.Item.DoWork();
    }
  }
}
公共类DisposableWrapper:IDisposable{
公共T项{get;私有集;}
公共可处置包装(T项){item=item;}
公共空间处置(){
使用(项作为IDisposable){}
项目=默认值(T);
}
}
公共静态类DisposableWrapperExtensions{
公共静态一次性包装(此T项){
退回新的一次性包装(物品);
}
}
公共类EngineedDriver,其中T:IEngine,new(){
public void gethingsdone(){
使用(var driver=new T().AsDisposable()){
driver.Item.DoWork();
}
}
}

如果您使用了许多可以实现IDisposable的接口引用,这可能是有意义的。谢谢您的回答,那么在处理完驱动程序后,驱动程序是否可以访问这个生命周期问题呢?@Michael:生命周期略有不同,但这并不是问题所在。我的意思是,这是使用变量的风险在它被释放之后,不是从性能或内存压力的角度。
public class DisposableWrapper<T> : IDisposable {
  public T Item { get; private set; }
  public DisposableWrapper(T item) { Item = item; }
  public void Dispose() {
    using (Item as IDisposable) { }
    Item = default(T);
  }
}

public static class DisposableWrapperExtensions {
  public static DisposableWrapper<T> AsDisposable<T>(this T item) {
    return new DisposableWrapper<T>(item);
  }
}

public class EngineDriver<T> where T : IEngine, new() {
  public void GetThingsDone() {
    using (var driver = new T().AsDisposable()) {
      driver.Item.DoWork();
    }
  }
}