1

我有一些代码可以将附件添加到电子邮件中。我通过类构造函数的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字节数组在哪里。我想正确处理每个附件和流,但是在发送消息之前我不能这样做,所以我正在考虑将它们添加到 a 中List<Attachment>List<Stream>然后遍历并调用 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();
    }
}

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

4

3 回答 3

5

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

MailMessage.Dispose将自动处理所有附件,这反过来将关闭/Dispose()所有底层流。

//other processing
emailClient.Send(message);
message.Dispose();  // Or just wrap this entire block in a using statement
于 2012-10-17T16:32:35.123 回答
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);
}
于 2012-10-17T16:33:02.960 回答
0

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

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

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

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

于 2012-10-17T16:42:01.717 回答