在对IDisposable的引用上调用dispose()

时间:2012-10-17 16:28:01

标签: c# email attachment idisposable

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

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<Attachment>List<Stream>然后迭代并呼吁处置。

这样的事情:

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();
    }
}

但是有些东西告诉我,如果仍然有一个没有收集垃圾或其他东西的参考文件,它将不会正确处理它们。有什么想法吗?

3 个答案:

答案 0 :(得分:5)

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

MailMessage.Dispose将自动处理所有附件,这些附件将关闭/ Dispose()所有基础流。

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

答案 1 :(得分:3)

这已由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);
}

答案 2 :(得分:0)

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

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

如果在完成使用之前处理流,则可以(并且可能已经执行过)观察此行为。即在您的邮件案例中,您可能会尝试在message.Attachments.Add(attach);之后立即处理流,这很可能会在Send来电期间导致“流处理”异常。

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