【问题标题】:Calling dispose() on a reference to an IDisposable对 IDisposable 的引用调用 dispose()
【发布时间】:2012-10-17 16:28:00
【问题描述】:

我有一些代码可以将附件添加到电子邮件中。我通过Attachment 类构造函数的Stream 重载添加它们。执行此操作的代码如下所示:

List<UploadedDocument> docs = DataBroker.GetUploadedDocs(Convert.ToInt32(HttpContext.Current.Session["offer_id"].ToString()));
//no need to keep this in session
HttpContext.Current.Session["offer_id"] = null;
int counter = 1;
foreach (UploadedDocument doc in docs)
{
    stream = new MemoryStream(doc.doc);
    attach = new Attachment(stream, "Attachment-" + counter.ToString());
    message.Attachments.Add(attach);              
}

其中doc.doc 是一个字节数组。我想正确处理每个附件和流,但在发送消息之前我不能这样做,所以我正在考虑将它们添加到 List&lt;Attachment&gt;List&lt;Stream&gt; 然后迭代并调用 dispose.

类似这样的:

List<Attachment> attachments;
List<Stream> streams;
//...
foreach(UploadedDocument doc in docs)
{
    stream = new MemoryStream(doc.doc);
    streams.Add(stream);
    attach = new Attachment(stream,"Name");
    attachments.Add(attach);
    message.Attachments.Add(attach);
}
//other processing
emailClient.Send(message);

if(attachments != null)
{
    foreach(Attachment attachment in attachments)
    {
        attachment.Dispose();
    }
}
if(streams != null)
{
    foreach(MemoryStream myStream in streams)
    {
        myStream.Dispose();
    }
}

但是有些东西告诉我,如果仍然有一个参考漂浮在周围,但没有得到垃圾收集或其他东西,那么它就不会正确处理它们。有什么想法吗?

【问题讨论】:

    标签: c# email attachment idisposable


    【解决方案1】:

    处理此问题的最简单方法是在MailMessage 上调用Dispose()

    MailMessage.Dispose 将自动处理所有附件,进而关闭/Dispose() 所有底层流。

    //other processing
    emailClient.Send(message);
    message.Dispose();  // Or just wrap this entire block in a using statement
    

    【讨论】:

    • 应该想到这一点。我猜我只是不相信MailMessageDispose() 会处理它的所有 资源。非常感谢。
    【解决方案2】:

    这已经被MailMessage.Dispose方法实现了:

    protected virtual void Dispose(bool disposing)
    {
        if (disposing && !this.disposed)
        {
            this.disposed = true;
            if (this.views != null)
            {
                this.views.Dispose();
            }
            if (this.attachments != null)
            {
                this.attachments.Dispose();
            }
            if (this.bodyView != null)
            {
                this.bodyView.Dispose();
            }
        }
    }
    

    只需将 MailMessage 的使用情况包装到 using 语句中,MailMessage 使用的所有资源将在您离开 using 块后释放:

    using(var message = new MailMessage(from, to))
    {
       foreach (UploadedDocument doc in docs)
       {
           stream = new MemoryStream(doc.doc);
           attach = new Attachment(stream, "Attachment-" + counter.ToString());
           message.Attachments.Add(attach);              
       }
    
       emailClient.Send(message);
    }
    

    【讨论】:

    • 谢谢!我应该想到这一点——只是不想盲目相信MailMessageDispose() 方法。猜猜这就是文档的用途。但是谁有时间呢? :P
    【解决方案3】:

    已经有正确方式的回复(MailMessage.Dispose),所以“如果仍有参考,请妥善处理它们......”:

    Dispose 将(也预期)在调用时释放资源,而不管谁引用了该对象。一种常见的方法是在实现 Dispose 的对象中也有内部标志,该标志将通过抛出“Object Disposed”异常来阻止任何进一步的调用。

    如果您在使用完流之前处理流,您可以(并且可能已经这样做)观察到这种行为。 IE。在您的邮件案例中,您可以尝试在message.Attachments.Add(attach); 之后立即处理流,这很可能会导致稍后在Send 调用期间出现“流处理”异常。

    请注意,有些对象(如 MemoryStream)在 Dispose 之后具有特殊定义的行为。 IE。 MemoryStream 会阻止除 ToArray/Lenght/GetBuffer 之外的所有调用,因为此类的主要目的之一是为您提供流的结果字节数组。作为副作用MemoryStreamDispose 本质上只是设置标志来阻止其他调用(这很好,因为这个类没有任何本机资源)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-02
      • 2018-03-23
      • 2017-10-27
      • 1970-01-01
      • 2011-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多