C#如何正确处理SmtpClient?

JL.*_*JL. 31 c# .net-4.0

VS 2010代码分析报告如下:

警告4 CA2000:Microsoft.Reliability:在方法'Mailer.SendMessage()'中,对象'client'未沿所有异常路径放置.对所有对它的引用超出范围之前,在对象'client'上调用System.IDisposable.Dispose.

我的代码是:

public void SendMessage()
    {
        SmtpClient client = new SmtpClient();

        client.Send(Message);
        client.Dispose(); 
        DisposeAttachments(); 
    }
Run Code Online (Sandbox Code Playgroud)

我该如何正确处理客户?

更新:回答Jons问题,这里是dispose附件功能:

private void DisposeAttachments()
{
    foreach (Attachment attachment in Message.Attachments)
    {
        attachment.Dispose();
    }
    Message.Attachments.Dispose();
    Message = null; 
}
Run Code Online (Sandbox Code Playgroud)

最后更新全班上市(简称)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Mail;

public class Mailer
    {
    public MailMessage Message
    {
        get;
        set;
    }

    public Mailer(MailMessage message)
    {
        this.Message = message; 
    }

    public void SendMessage()
    {
        using (SmtpClient client = new SmtpClient())
        {
            client.Send(Message);
        }
        DisposeAttachments(); 
    }

    private void DisposeAttachments()
    {
        foreach (Attachment attachment in Message.Attachments)
        {
            attachment.Dispose();
        }
        Message.Attachments.Dispose();
        Message = null; 
    }
    }
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 47

public void SendMessage()
{
    using (SmtpClient client = new SmtpClient())
    {
        client.Send(Message);
    }
    DisposeAttachments(); 
}
Run Code Online (Sandbox Code Playgroud)

这样,即使在Send方法调用期间抛出异常,客户端也将被丢弃.您应该很少需要Dispose显式调用- 它应该几乎总是在一个using语句中.

但是,目前还不清楚附件是如何涉及的.你的班级是否实现了IDisposable自己?如果是这样,那可能是处理附件的地方,这些附件可能是成员变量.如果你需要确保他们在这里处置,你可能需要:

public void SendMessage()
{
    try
    {
        using (SmtpClient client = new SmtpClient())
        {
            client.Send(Message);
        }
    }
    finally
    {
        DisposeAttachments(); 
    }
}
Run Code Online (Sandbox Code Playgroud)


Ste*_*ven 12

SmtpClient.NET 4.0中的类现在实现了IDisposable,而SmtpClient.NET 2.0中的类缺少这个接口(正如Darin所说).这是框架中的重大更改,您应该在迁移到.NET 4.0时采取适当的操作.但是,在迁移到.NET 4.0之前,可以在代码中缓解此问题.这是一个例子:

var client = new SmtpClient();

// Do not remove this using. In .NET 4.0 SmtpClient implements IDisposable.
using (client as IDisposable)
{
    client.Send(message);
} 
Run Code Online (Sandbox Code Playgroud)

此代码将在.NET 2.0(+3.0和3.5)和.NET 4.0下正确编译和运行.

  • @Nyerguds:不是想象,为什么不测试它,就像我在写下这个答案之前所做的那样? (4认同)

Dar*_*rov 7

using (SmtpClient client = new SmtpClient())
{
    client.Send(Message);
    DisposeAttachments(); 
}
Run Code Online (Sandbox Code Playgroud)

有趣 - 与.NET 3.5相反,SmtpClient在.NET 4.0中实现IDisposable,每天都在学习新东西.

  • 警告 - 如果您没有使用网络传递方法,并且尚未设置Host属性,则Dispose方法将抛出InvalidOperationException!http://connect.microsoft.com/VisualStudio/feedback/details/539160/smtpclient-reports-invalidoperationexception-when-disposed-immediatelly-after-sending-mail-and-pickup-directory-is-used (2认同)

Mor*_*dur 5

我会做那样的事情:

class Attachments : List<Attachment>, IDisposable
{
  public void Dispose()
  {
    foreach (Attachment a in this)
    {
      a.Dispose();
    }
  }
}

class Mailer : IDisposable
{
  SmtpClient client = new SmtpClient();
  Attachments attachments = new Attachments();

  public SendMessage()
  {
    [... do mail stuff ...]
  }

  public void Dispose()
  {
    this.client.Dispose();
    this.attachments.Dispose();
  }
}


[... somewhere else ...]
using (Mailer mailer = new Mailer())
{
  mailer.SendMail();
}
Run Code Online (Sandbox Code Playgroud)

如果要发送多封邮件,这将允许重用SmtpClient对象.