如何正确实现IDisposable

时间:2015-12-28 16:59:12

标签: c# asp.net idisposable ca1001

我是C#的新手,我遇到了以下警告信息:

  

警告CA1001实施IDisposable   'form_Inspection_Upload.d__4',因为它创建   以下IDisposable类型的成员:'StringReader',   'WebServicesSoapClient'

这是使用VS Express 2015 for Desktop,Windows 7操作系统进行重建的结果。我查看了各种类似消息的帖子,但未能看到它们如何适用于下面显示的代码。上面的警告说'StringReader'对象(“a_string_reader”)需要处理?如果是这样,为什么在“USING子程序结束后”没有处理它?<​​/ p>

在同一代码块中进一步向下是'WebServicesSoapClient'对象(“ebws”)。据我所知,它没有Dispose方法,但可以关闭。关闭服务客户端是否与将其删除无关?显然,不,但我不确定如何在https://msdn.microsoft.com/library/ms182172.aspx上显示IDisposable

如果它有帮助,这里是代码。有问题的部分是倒数第三个代码块(重要部分包含注释// important line。):

        private async void button_Upload_Click(object sender, EventArgs e)
        {
           using (StringReader a_string_reader = new StringReader(pdf_doc_string)) // important line
                { do
                    {
                      a_line = a_string_reader.ReadLine(); 
                    } while (a_line != null);
                }

                eBridge.WebServicesSoapClient ebws = new eBridge.WebServicesSoapClient(); // important line
                eBridge.FileUploadResponse upload_result = await ebws.FileUploadAsync(User, Password, Cabinet, b, File_Path, Index1_Program, Index2_Permit_Number, Index3_Name, Index4_Address, Index5_ZipCode, Index6_Doc_Date, Index7_Doc_Type);

                ebws.Close(); // important line
            }
        }

1 个答案:

答案 0 :(得分:1)

我遇到过马克·西曼的博客&#39; ploeh博客&#39;文章&#34;如何从表格中处理成员&#34; (http://blogs.msdn.com/b/ploeh/archive/2006/08/10/howtodisposemembersfromforms.aspx)以点击给我的方式解决了这个问题。谢谢你!同样非常有帮助的是Henk指出警告适用于成员。

请不要犹豫,纠正或澄清这个帖子,因为我对C#和相关术语的了解非常新手。

简短的回答是为每个需要处理的对象创建一个公共类,并将子类IDisposable添加到对象&#39;基类。在类中为对象创建Dispose方法。然后将该项目带入表单。

更详细的解释如下:

  • 创建了一个Web服务的公共类,它包含了IDisposable

. public class eBWS : eBridge.WebServicesSoapClient, IDisposable { public eBWS(<arguments>) { this.FileUploadExAsync(<arguments>); } public void Dispose() { } }

在button_Upload_Click方法中,替换了

. using (eBridge.WebServicesSoapClient ebws = new eBridge.WebServicesSoapClient()) { eBridge.FileUploadResponse upload_result = await ebws.FileUploadAsync(<arguments>); textBox_Results.Text = upload_result.ToString(); }

. ebws = new eBWS(<arguments>);

对StringReader对象使用了类似的方法,但现在遇到了另一个问题。这里不解决它。

如果博客应该从网上消失,那么完整的文字就会出现(再次,感谢Mark Seemann博客&#39; ploeh博客&#39;文章&#34;如何从表格中处理成员& #34):

  

2006年8月5:22    19

当您创建新表单(或UserControl)时,Visual Studio会将其创建为部分类,设计器生成的代码将进入* .Designer.cs文件。设计代码中的另一段代码是System.ComponentModel.Component.Dispose(bool)的覆盖,它包含处理表单及其包含的组件的代码。它总是这样:

protected override void Dispose(bool disposing)
{
    if (disposing && (components != null))
    {
        components.Dispose();
    }
    base.Dispose(disposing);
}

有点不幸的是,这个方法被覆盖了,因为它使你自己的处理逻辑添加到表单更加困难,因为你不能再次在同一个类中覆盖该方法 - 请记住,您控制的表单代码只是类定义的一部分。您显然可以直接编辑设计器文件,但不建议这样做。

如果您需要在表单中执行一些额外的处置逻辑,那么您可以做什么?如果你的一个成员变量实现了IDisposable,那么这个需求很容易就会到来,在这种情况下你真的应该在Form处理时处理掉它。想象一下,你有以下IDisposable类:

public class MyDisposable : IDisposable
{
    private string message_;

    public MyDisposable(string message)
    {
        this.message_ = message;
    }

    #region IDisposable Members

    public void Dispose()
    {
        MessageBox.Show(this.message_);
    }

    #endregion
}

您现在希望在表单中有一个MyDisposable成员变量,并且在表单处理时需要处理它:

    public partial class MyForm : Form
    {
        private MyDisposable myDisposable_;

        public MyForm()
        {
            InitializeComponent();

            this.myDisposable_ =
            new MyDisposable("Goodbye, World");
        }
    }

当您运行应用程序并关闭表单时,表单正在处理,但您从未看到再见消息,因为myDisposable_未被处理。设计器代码中的Dispose方法处理表单的dispose逻辑,它对myDisposable_成员变量一无所知。

然而,它确实处理了它的组件成员,并且由于这是一个IContainer,如果你可以将myDisposable_添加到容器中,问题就解决了。不幸的是,IContainer只接受IComponent实例,如果您不想在MyDisposable上实现IComponent。

IComponent合同的一部分是实现必须有一个默认构造函数,并且出于API设计原因,您可能找不到可接受的IDisposable类型 - 出于某种原因,我不认为&#39 ;对于MyDisposable来说,这是一个可接受的变化。

但是,您可以做的是将这个小类的实例添加到容器中:

    internal class Disposer : Component
    {
        private Action<bool> dispose_;

        internal Disposer(Action<bool> disposeCallback)
        {
            this.dispose_ = disposeCallback;
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);

            this.dispose_(disposing);
        }
    }

从表单代码中,您需要将一个新的Disposer实例与一个包含真实配置逻辑的委托连接起来。在MyForm中使用时,它现在看起来像这样:

    public partial class MyForm : Form
    {
        private MyDisposable myDisposable_;

        public MyForm()
        {
            InitializeComponent();

            this.myDisposable_ =
            new MyDisposable("Goodbye, World");
            this.components.Add(new Disposer(this.OnDispose));
        }

        private void OnDispose(bool disposing)
        {
            this.myDisposable_.Dispose();
        }
    }

请注意,我添加了一个新的Disposer实例,该实例指向新的OnDispose方法,然后该方法实现了设计器代码未处理的所有dispose逻辑。现在,当我运行应用程序并关闭Form时,我得到了预期的MessageBox。

这种技术通常可以在需要处理成员变量时使用,但由于设计器代码已经覆盖了Dispose方法,因此无法使用。但是,如果您的成员变量也没有实现IComponent,我只推荐这种方法。

如果您可以控制成员变量的类并且不介意使用默认构造函数,我建议您改为实现IComponent(最简单的方法是从System.ComponentModel派生) .Component就像我使用Disposer类一样)。这通常会为您提供更好的设计时体验,因为您现在可以将组件从工具箱拖到设计图面,设计器(Visual Studio)会自动将其添加到组件成员变量中,因此它将是与容器中的所有其他组件一起放置。

如果您正在创建UserControl,这两种方法也都有效,尽管如此,您可能需要自己实例化组件成员变量。