【问题标题】:Extract method in C# to use throughout projectC# 中的提取方法以在整个项目中使用
【发布时间】:2012-06-04 03:22:13
【问题描述】:

请原谅这里的冗长代码,我也意识到这对于任何面向对象的开发人员来说可能是一个非常基本的基本问题,但我是一名前端开发人员,深谙 .NET 并试图了解带有实际示例的类和方法。我已经阅读了解释这些东西的资源,但立即被现实世界代码的复杂性所困扰。

基本上,我有很多方法可以将 cmets 添加到网页和操作状态(标记为垃圾邮件、删除等)。其中许多方法称为“EmailNotification”方法,该方法在每个阶段向管理员发送电子邮件。效果很好。

但是,我想在项目的其他地方使用“EmailNotification”方法,从不同的 .cs 文件中调用它。当我尝试这样做时,它无法识别该方法,因为(我认为!?)它不是公共静态方法。

谁能向我解释如何提取 EmailNotification 方法,以便我可以在代码周围的不同位置使用它?我尝试在其中创建一个包含此方法的新类,但我无法让它工作。

using System;
using System.Net.Mail;

namespace UComment.Domain
{
public class Comment
{
    public delegate void CommentCreatedEventHandler(Comment sender, EventArgs e);
    public delegate void CommentDeletedEventHandler(Comment sender, EventArgs e);
    public delegate void CommentSpamEventHandler(Comment sender, EventArgs e);
    public delegate void CommentApprovedEventHandler(Comment sender, EventArgs e);

    public static event CommentCreatedEventHandler CommentCreated;
    public static event CommentDeletedEventHandler CommentDeleted;
    public static event CommentSpamEventHandler CommentSpam;
    public static event CommentApprovedEventHandler CommentApproved;

    protected virtual void OnCommentCreated(EventArgs e)
    {
        if (CommentCreated != null) CommentCreated(this, e);
    }

    protected virtual void OnCommentSpam(EventArgs e)
    {
        if (CommentSpam != null) CommentSpam(this, e);
    }

    protected virtual void OnCommentApproved(EventArgs e)
    {
        if (CommentApproved != null) CommentApproved(this, e);
    }

    protected virtual void OnCommentDelete(EventArgs e)
    {
        if (CommentDeleted != null) CommentDeleted(this, e);
    }


    public int Id { get; set; }
    public int ParentNodeId { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public string Website { get; set; }
    public bool Spam { get; set; }
    public bool Approved { get; set; }
    public DateTime Created { get; set; }
    public string CommenText { get; set; }
    public int StatusId { get; set; }

    public Comment(int id)
    {
        Id = id;
        var sqlHelper = DataLayerHelper.CreateSqlHelper(cms.GlobalSettings.DbDSN);
        var reader = sqlHelper.ExecuteReader("select * from Comment where id = @id",
                                             sqlHelper.CreateParameter("@id", id));

        if(!reader.HasRecords) throw new Exception(string.Format("Comment with id {0} was not found", id));

        reader.Read();

        Name = reader.GetString("name");
        ParentNodeId = reader.GetInt("nodeid");
        Email = reader.GetString("email");
        Website = reader.GetString("website");
        Approved = reader.GetBoolean("approved");
        Spam = reader.GetBoolean("Spam");
        Created = reader.GetDateTime("created");
        CommenText = reader.GetString("comment");
        StatusId = reader.GetInt("statusid");
    }

    private Comment()
    {
    }

    /// <summary>
    /// Set as approved, mark as Not Spam - ignore HAM status
    /// </summary>
    public void MarkAsApproved()
    {
        var sqlHelper = DataLayerHelper.CreateSqlHelper(cms.GlobalSettings.DbDSN);
        sqlHelper.ExecuteNonQuery(
             "update comment set approved = 1, spam = 0, statusid = 2 where id = @id",
             sqlHelper.CreateParameter("@id", Id));

        OnCommentApproved(EventArgs.Empty);

        // Send approval email
        EmailNotification(1);

    }

    /// <summary>
    /// Remove approval status. Ignore Spam and Ham states
    /// </summary>
    public void MarkAsNotApproved()
    {
        var sqlHelper = DataLayerHelper.CreateSqlHelper(cms.GlobalSettings.DbDSN);
        sqlHelper.ExecuteNonQuery(
             "update comment set approved = 0, statusid = 3 where id = @id",
             sqlHelper.CreateParameter("@id", Id));

        OnCommentApproved(EventArgs.Empty);

        // Send rejection email
        EmailNotification(2);
    }



    /// <summary>
    /// Spam cannot be ham or approved
    /// </summary>
    public void MarkAsSpam()
    {
        var sqlHelper = DataLayerHelper.CreateSqlHelper(cms.GlobalSettings.DbDSN);
        sqlHelper.ExecuteNonQuery(
             "update comment set spam = 1, ham = 0, approved = 0, statusid = 3 where id = @id",
             sqlHelper.CreateParameter("@id", Id));

        OnCommentSpam(EventArgs.Empty);

        // No email notification required - spammer not worthy of a reason for rejection
    }


    /// <summary>
    /// Ham is "not spam" - approved comments from Akismet. 
    /// </summary>
    public void MarkAsHam()
    {
        var sqlHelper = DataLayerHelper.CreateSqlHelper(cms.GlobalSettings.DbDSN);
        sqlHelper.ExecuteNonQuery(
           "update comment set spam = 0, ham = 1 where id = @id",
           sqlHelper.CreateParameter("@id", Id));

        // No email notification required, simply marking spam as ham
    }

    public void Delete()
    {
        if (Id < 1) return;

        var sqlHelper = DataLayerHelper.CreateSqlHelper(cms.GlobalSettings.DbDSN);
        sqlHelper.ExecuteNonQuery("delete from comment where id = @id", sqlHelper.CreateParameter("@id", Id));

        Id = -1;
        OnCommentDelete(EventArgs.Empty);

        // Permanent deletion
    }

    public void Reject()
    {
        if (Id < 1) return;

        var sqlHelper = DataLayerHelper.CreateSqlHelper(cms.GlobalSettings.DbDSN);
        sqlHelper.ExecuteNonQuery("update comment set statusid = 3 where id = @id", sqlHelper.CreateParameter("@id", Id));

        //Id = -1;
        //OnCommentDelete(EventArgs.Empty);

        // Send rejection email
        EmailNotification(2);
    }




    public static Comment MakeNew(int parentNodeId, string name, string email, string website, bool approved, bool spam, DateTime created, string commentText, int statusId)
    {

        var c = new Comment
            {
                ParentNodeId = parentNodeId,
                Name = name,
                Email = email,
                Website = website,
                Approved = approved,
                Spam = spam,
                Created = created,
                CommenText = commentText,
                StatusId = statusId
            };

        var sqlHelper = DataLayerHelper.CreateSqlHelper(cms.GlobalSettings.DbDSN);

        c.Id = sqlHelper.ExecuteScalar<int>(
            @"insert into Comment(mainid,nodeid,name,email,website,comment,approved,spam,created,statusid) 
                values(@mainid,@nodeid,@name,@email,@website,@comment,@approved,@spam,@created,@statusid)",
            sqlHelper.CreateParameter("@mainid", -1),
            sqlHelper.CreateParameter("@nodeid", c.ParentNodeId),
            sqlHelper.CreateParameter("@name", c.Name),
            sqlHelper.CreateParameter("@email", c.Email),
            sqlHelper.CreateParameter("@website", c.Website),
            sqlHelper.CreateParameter("@comment", c.CommenText),
            sqlHelper.CreateParameter("@approved", c.Approved),
            sqlHelper.CreateParameter("@spam", c.Spam),
            sqlHelper.CreateParameter("@created", c.Created),
            sqlHelper.CreateParameter("@statusid", c.StatusId));

        c.OnCommentCreated(EventArgs.Empty);

        if (c.Spam)
        {
            c.OnCommentSpam(EventArgs.Empty);
        }

        if (c.Approved)
        {
            c.OnCommentApproved(EventArgs.Empty);
        }

        return c;
    }

    public override string ToString()
    {
        return @"ParentNodeId " + ParentNodeId + @"
        Name " + Name + @"
        Email " + Email + @"
        Website " + Website + @"
        Approved " + Approved + @"
        Spam " + Spam + @"
        Created "+ Created + @"
        CommenText " + CommenText + Environment.NewLine;
    }


    /// <summary>
    /// Send email notification
    /// </summary>
    public void EmailNotification(int notificationType)
    {

        var uCommentAdminEmail = Config.GetUCommentSetting("uCommentAdminEmail");

        MailAddress to = null;
        MailAddress from = new MailAddress(uCommentAdminEmail);
        string subject = null;
        string body = null;

        switch (notificationType)
        {
            case 1:
                // Comment approved
                to = new MailAddress("me@mydomain.com");
                subject = "Comment approved";
                body = @"The comment you posted has been approved";
                break;
            case 2:
                // Comment rejected
                to = new MailAddress("me@mydomain.com");
                subject = "Comment rejected";
                body = @"The comment you posted has been rejected";
                break;
        }

        MailMessage message = new MailMessage(from, to);
        message.Subject = subject;
        message.Body = body;
        SmtpClient client = new SmtpClient();           

        try
        {
            client.Send(message);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception caught in EmailNotification: {0}", ex.ToString());
        }
        finally
        {
            //
        }


    }


}
}

感谢大家的指点!

【问题讨论】:

  • 另外,从 sqlHelper.ExecuteReader 调用返回的 SqlDataReader 应该在 using 块中。

标签: c# oop methods


【解决方案1】:

你可以:

  1. 将其提取到静态类的静态方法中
  2. 创建具有实例方法的单例类
  3. 为 MessageSender 创建一个类和接口,并使用 DI 将其注入到需要的地方。

这取决于项目的规模:对于小型项目 1. 可能就足够了,对于大型和复杂的(如果您有 DI)则需要 3 个。

【讨论】:

    【解决方案2】:

    这里有一个公共方法,但是因为它没有声明为静态 (public static void EmailNotification...),所以如果不创建它所在的类的实例,就无法使用它。

    using System;
    
    namespace UComment.Domain
    {
        public class MyOtherClass
        {
             public void MyMethod()
             {
                 Comment c = new Comment();
                 c.EmailNotification(1);
             }
        }
    }
    

    你可以声明静态方法,这样你就可以这样调用它:

    using System;
    
    namespace UComment.Domain
    {
        public class MyOtherClass
        {
             public void MyMethod()
             {
                 Comment.EmailNotification(1);
             }
        }
    }
    

    如果您尝试从不同的命名空间使用它,那么您需要通过 using 语句或通过指定完整的命名空间内联来包含该命名空间。

    using System;
    using UComment.Domain;
    
    namespace UComment.OtherNamespace
    {
        public class MyOtherClass
        {
             public void MyMethod()
             {
                 Comment c = new Comment();
                 c.EmailNotification(1);
             }
        }
    }
    

    或者

    using System;
    
    namespace UComment.OtherNamespace
    {
        public class MyOtherClass
        {
             public void MyMethod()
             {
                 UComment.Domain.Comment c = new UComment.Domain.Comment();
                 c.EmailNotification(1);
             }
        }
    }
    

    你的想法是正确的,如果你想让它成为一个通用方法,它应该独立于 Comment 类。我刚才描述的相同限制也适用于这样做。此外,您必须确保任何适当的 using 语句都在新类上,并且 EmailNotification 中的依赖关系也被考虑在内。

    【讨论】:

    • 谢谢杰米。当我将 EmailNotification 方法设置为“静态”时,我总是会收到一条错误消息,提示“方法必须具有返回类型”。它没有返回任何东西,所以我很困惑在这里做什么?
    • 如果你没有返回任何东西,返回类型应该是 void 即public static void EmailNotification(... static 是一个指定行为的关键字,所以它除了不是而不是返回类型.
    • 意识到我在输入部分答案时漏掉了 void 这个词并修复了它。对不起,错字令人困惑。手指偶尔跟不上大脑。
    • 点击了某些东西!谢谢,这有点道理:)
    【解决方案3】:

    你的班级做的东西太多了!

    把它分成不同的类型,每个人只需要根据Separation of concerns解决一种问题。

    电子邮件发送也是如此,创建一个 EmailSender 类(或其他名称)并将 Send 方法集中在那里。

    您还可以创建一个接口(例如ISmtpClientFactory)传递给EmailSender 类,以抽象具体系统发送电子邮件并改善测试体验。

    只有在你真正发送邮件的生产环境中,在测试环境中你可以使用假工厂来模拟发送。

    public class EmailSender
    {
        private readonly ISmtpClientFactory factory;
    
        public EmailSender(ISmtpClientFactory factory)
        {
            this.factory = factory;
        }
    
        public void Send(MailMessage message)
        {
            using (var client = factory.Create())
            {
                using (message)
                {
                    client.Send(message);
                }
            }
        }
    }
    
    new EmailSender(new SmtpClientFactory()).Send(AdviceMessageFactory.Create(...));
    

    【讨论】:

    • 我完全同意你的观点 Matteo。我只是真的认为在重新考虑之前我需要尝试掌握正在发生的事情的基本知识 - 我只是没有技能。也许如果原始代码的结构更好,我会有更多的机会理解它,并且从中学习会更好,但我有点坚持我所拥有的。不过谢谢,我认为你是对的。
    【解决方案4】:

    您可以将它放在它自己的类中(就像您已经尝试过的那样)并使方法静态。

    如果这个新类是 EmailHelper,你可以这样调用方法:

    EmailHelper.EmailNotification(1);
    

    根据新类的命名空间,您可能还需要在使用它的每个文件的顶部添加一条 using 语句。

    【讨论】:

    • 谢谢。我试过这个。我已经删除了“EmailNotification”方法并将其粘贴到一个新类中,例如public class EmailHelper { ...method in here... }。但是,现在所有对 EmailNotification 方法的引用都报错(“名称 'EmailNotification' 在当前上下文中不存在”)。我尝试将这些引用更改为 EmailHelper.EmailNotification(1),但也出现此错误(“非静态字段、方法或属性 'UComment.Domain.EmailHelper.EmailNotification(int) 需要对象引用”)。
    【解决方案5】:

    如果您创建一个(公共)类并在其中包含该方法,它看起来不会引起任何问题。该方法应该接受发送电子邮件所需的所有属性。您可以创建该类的实例并调用该方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-08
      • 1970-01-01
      • 2014-03-27
      • 1970-01-01
      • 2020-08-07
      • 2016-05-20
      • 1970-01-01
      相关资源
      最近更新 更多