1

我有一个问题,我正在尝试使用这样的一种结构发送邮件:

private void SendMail()
{

    var client = new SmtpClient("smtp.gmail.com", 587)
    {
        Credentials = new NetworkCredential("mymail@mail.com", "mypassword"),
        EnableSsl = true
    };
    client.Send("mymail@mail.com", "AdressClient@mail.com", "Subject", "Body");
}

好吧,这个结构工作得很好,但是会导致我的主程序出现延迟,因此我想在另一个线程中执行 SendMail 函数,如下所示:

private void ButtonTestSendMail_Click(object sender, EventArgs e)
    {
        //THREAD
        Thread ThreadSendEmail = new Thread(new ThreadStart(this.SendMail));
        ThreadSendEmail .IsBackground = true;
        ThreadSendEmail .Start();
    }


private void SendMail()
{   
   var client = new SmtpClient("smtp.gmail.com", 587)
   {
      Credentials = new NetworkCredential("mymail@mail.com", "mypassword"),
      EnableSsl = true
   };
   client.Send("mymail@mail.com", "AdressClient@mail.com", "Subject", "Body");
}

好吧,此时我注意到我需要更改邮件的参数,例如 AdressClient@mail.com、Suject 和 Body。

但我不知道如何:/

如何编写一个接受参数的线程,如下所示:

private void ButtonTestSendMail_Click(object sender, EventArgs e)
        {
            string Body = "BodyTest";
            string AdressMail = "AdressMail@test.com";
            string Subject = "SubjectTest";
        //THREAD
        Thread ThreadSendEmail = new Thread(new ThreadStart(this.SendMail(Body,AdressMail,Subject));
        ThreadSendEmail .IsBackground = true;
        ThreadSendEmail .Start();
    }


    private void SendMail(string Body, string Adress, string Subject)
    {   
       var client = new SmtpClient("smtp.gmail.com", 587)
       {
          Credentials = new NetworkCredential("mymail@mail.com", "mypassword"),
          EnableSsl = true
       };
       client.Send("mymail@mail.com", Adress, Subject, Body);
    }

我试过但没有用,我有一个 MethodName Expected 和一个错误通知在这一行:

Thread ThreadSendEmail = new Thread(new ThreadStart(this.SendMail(Body,AdressMail,Subject));

如何编写接受参数的线程?谢谢你的帮助!此致!

4

4 回答 4

2

您快到了:

Thread ThreadSendEmail = new Thread(() => this.SendMail(Body,AdressMail,Subject));

lambda 可以解决问题。您不能直接调用 SendMail,您想将其作为未调用的函数传递。

请注意,如果您的 ASP.NET 进程回收(可能是因为您正在部署),该线程将被粗鲁地中止。然后邮件将丢失。

于 2013-03-02T22:20:24.227 回答
2

如果您需要做的只是异步发送邮件消息,您可以使用SmtpClient.SendAsync方法并且您的调用线程不会被阻塞(http://msdn.microsoft.com/en-us/library/x5x13z6h.aspx) .

但是如果你真的想要一个新线程来完成这项工作,你需要创建一个包含你的参数值的类,并使用ParameterizedThreadStart委托来实例化它。这是一个带有一个示例的 SO 条目: 带参数的 ThreadStart

于 2013-03-02T22:27:50.580 回答
1

显式地创建自己的线程通常没有必要,有时甚至是个坏主意。相反,您可以利用 .NET ThreadPool 在现有但非主线程上启动工作。例如:

ThreadPool.QueueUserWorkItem(state => { /* threadpool work */ }, null);

无论哪种方式,在另一个线程上工作都可能很危险,因为如果抛出(而不是捕获)任何异常,您的应用程序将终止。此外,唯一的效果Thread.IsBackground = true是不阻止您的应用程序在运行时退出。如果您的意图是更改线程优先级,则应设置不同的属性。

如果您使用的是 .NET 4.0,则可以使用更高级别的抽象来帮助您处理异常:

Task task = Task.Factory.StartNew(() => { /* threadpool work */ });

稍后,如果在任务中引发异常,您可以观察它并根据需要使用 Task 对象上的各种属性和方法做出反应。在 .NET 4.0 上,如果您没有观察到异常,而只是让任务获得 GC,它也会使您的应用程序崩溃(尽管在一个不确定的时间,每当终结器运行时)。在 .NET 4.5 上,您的应用不会在这种情况下崩溃。

最后,如果您使用的是 .NET 4.5,则可以变得更短:

Task task = Task.Run(() => { /* threadpool work */ });
于 2013-03-02T22:31:57.977 回答
0

Thread.Start()方法具有object传递给线程方法的第二个参数的重载 - 因此您可以执行以下操作:

Thread ThreadSendEmail = new Thread(new ThreadStart(this.SendMail));
ThreadSendEmail.IsBackground = true;
ThreadSendEmail.Start("Body test");

. . . .

private void SendMail(object data)
{
  string body = (string)data;
  . . . 
}

如果您想/需要传递更多参数,请将它们捆绑在一个对象中,然后传递该对象。

除了创建线程之外,您还可以使用线程池,它可以更好地扩展并且更易于使用,只需一行代码:

ThreadPool.QueueUserWorkItem(new WaitCallback(SemdMail), "Body test");

PS这是“旧式”解决方案,“现代”解决方案是使用 lambdas - 请参阅@usr 答案。

于 2013-03-02T22:21:23.627 回答