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 に追加してから、繰り返し処理して dispose を呼び出すことを考えていまし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();
    }
}

しかし、ガベージコレクションなどを取得していない参照がまだ浮かんでいる場合、それらを適切に破棄しないことがわかります。何かご意見は?

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 は、オブジェクトへの参照を誰が持っているかに関係なく、呼び出しの時点でリソースを解放します (これも予想されます)。一般的なアプローチの 1 つは、"Object Disposed" 例外をスローしてそれ以降の呼び出しをブロックする Dispose を実装するオブジェクトに内部フラグを持たせることです。

ストリームを使用する前にストリームを破棄すると、この動作を確認できます (おそらく既に確認しています)。つまり、メールの場合、ストリームをすぐに破棄しようとすると、message.Attachments.Add(attach);後で呼び出し中に「ストリームが破棄されました」という例外が発生する可能性がありSendます。

Dispose 後に特別に定義された動作を持つ MemoryStream のようなオブジェクトがいくつかあることに注意してください。つまり、MemoryStream は、ToArray/Lenght/GetBuffer を除くすべての呼び出しをブロックします。これは、このクラスの主な目的の 1 つは、ストリームの結果のバイト配列を提供することだからです。副作用として、基本的にフラグを設定して他MemoryStreamDispose呼び出しをブロックするだけです(このクラスにはネイティブリソースがないため、これは問題ありません)。

于 2012-10-17T16:42:01.717 に答える