【问题标题】:How to call a method implicitly after every method call?如何在每次方法调用后隐式调用方法?
【发布时间】:2016-01-09 14:05:51
【问题描述】:

抱歉,帖子的标题太棒了。我有点想知道下面的问题是否有任何解决方案。情况是我有一个名为SaveSecurity(); 的函数,我需要在每个函数之后调用它。如下:

public void AddUser(string ID, string Name, string Password)
{
    ///some codes
    SaveSecurity();
}
public void DeleteUser(User ObjUser)
{
    ///some codes
    SaveSecurity();
}
public void AddPermission(string ID, string Name, AccessType Access)
{
    ///some codes
    SaveSecurity();
}
public void DeletePermission(Permission ObjPermission)
{
    ///some codes
    SaveSecurity();
}
public void AddRole(string ID, string Name)
{
    Roles.AddRole(ID, Name);
    SaveSecurity();
}
public void SaveSecurity()
{
    ///Saves the data
}

还有更多。所以现在如果我们看一下所有函数的相似之处是它最后在函数结束后调用SaveSecurity()。我的问题是:

有没有办法在每个函数之后调用这个函数而不用一遍又一遍地写同一行?

我的类图是这样的

【问题讨论】:

  • 您可以考虑方面方法(例如 PostSharp),但即使在这种情况下,您也必须指定(例如通过属性)哪些方法应该调用 SaveSecurity...
  • 您可能想查看AOP。 .NET 世界中有几个 AOP 解决方案/框架,如 Spring.NET、PostSharp 和一些 IoC 容器。见stackoverflow.com/questions/633710/…
  • 当然会想到 AOP,但我认为它是解决这个问题的错误工具,因为它不是另一个“关注”,例如日志记录。对我来说,SaveSecurity() 对方法很重要,应该直接放入其中...
  • @RicoSuter 如果它是必要的,那么不要通过将它移动到某个地方来自动化它,你可能会在它存在的时候“忘记”它。代码需要非常精确和清晰。而且我认为,如果它是函数的强制性部分,您要么每次都编写它,要么将它提取为一个辅助类并应用类似template method pattern
  • @RicoSuter:其实我同意你的看法。我无法说出这句话来形容它。感谢您的描述。 :)

标签: c#


【解决方案1】:

您需要研究存储库模式,

将你的类和那里的操作分开,

创建另一个层(称为业务层)或任何将调用不同类的不同方法的层...

您正在尝试遵循 OOP 的 ATM,但您所做的只是函数式编程..

Implementing the Repository and Unit of Work Patterns in an ASP.NET MVC Application

添加类图后编辑

您的集合类实际上是存储库类,您需要将您的方法(如 deletePermissions、deleteRole)移动到相应的存储库类,如 permissionsRepo(如果需要,将其命名为集合)和 roleRepo..

所以你已经有一个对象类和一个对象的存储库类(可以在一起),但我喜欢将它们分开,存储库类会做他们需要做的事情,比如..

// Make changes to DB
// Make changes to AD
// Makes changes to web services etc...

您的管理器类可能会复制存储库类的方法,但它们只会调用它们,

PermissionManager.DeletePermissions(PermissionObject);

然后在 PermissionManager 类中,您将拥有方法,

DeletePermissions(Permissions pObject)
{
     PermissionRepo.Delete(pObject);
}

上面只是添加一个层,让您的代码在很短的时间内看起来更具可读性和面向未来,但如果您有更多时间投入,您也可以研究观察者模式......

Implement Observer pattern in C#

每次您的对象更改其状态时,您都可以调用 SaveSecurity 方法(该方法将在另一个类中(可能会更改名称)。如果您不想为每次更改对象调用 SaveSecurity,您可以添加一个您的对象的属性,例如 IsSecurityChanged ?如果是,则调用 SaveSecurity。

更多解释,但如果你看看上面的观察者模式你就会明白。

另外一种方法,但我个人不推荐,使用 IDisposable 接口,然后在 dispose 方法中调用对象的 SaveSecurity 方法。 但我不推荐它。

【讨论】:

【解决方案2】:

仅使用 C# 是不行的,但有一些解决方案可能会有所帮助。

我知道的最好的是PostSharp。它将使您能够在调用方法之前和之后定义操作(例如)。关于它的一些信息可以在herehere找到。

你唯一需要做的就是用一个属性来装饰你想要调用SaveSecurity的方法。

如果您不想使用此类工具,请保持原样。就这样没关系。

【讨论】:

  • 让我看看。它对我来说是新的,因此对我来说是新的知识。希望对我有帮助。
  • 你说他不能只用 C#,但我认为只通过自省应该是可能的......
  • @sha 你能举个例子吗?
  • 我做的最相似的事情(我没有保留源代码......)是检查类的方法,获取它们的主体并从中创建新功能。我不知道是否可以替换原来的主体,但如果可以的话,它会回答这个问题。
  • 在每个方法之前需要一个属性装饰器比在最后需要一个函数调用更好吗?您很可能会忘记另一个,并且它并不能解决重复代码的问题,只是将其从方法的底部移到顶部。充其量,这可能会增加它的可见性,让你更容易看到你是否错过了一个,但实际上它只是增加了另一个移动部分,这会带来更多的出错空间。
【解决方案3】:

您可以使用某种面向方面的编程(不知道如何在 C# 中进行,但尝试使用谷歌搜索)。

另一种不会比简单地在另一个函数末尾调用一个函数更好的方法是创建带有函数参数的辅助函数,该函数执行其参数,然后调用您的安全函数。但是每个函数的主体看起来像(如果我没记错 C# lambda):

CallAndSaveSecurity(() => /* some code */);

所以它会包含与您原来的解决方案一样多的东西。

顺便说一句,也许您在通话中需要更多。如果您希望即使发生异常也能调用该函数,则需要

try{
  // some code
} finally {
  SaveSecurity();
}

将其隐藏到函数式助手中是有意义的。

【讨论】:

  • 这个主意不错。但这并不能解决我的问题。 Bcoz 我的代码仍然看起来一样。还有其他想法吗??
【解决方案4】:
using System;

namespace Shweta.Question
{
   public class User
   { }
   public class Permission
   { }

   public enum AccessType
   {
      none,
      full,
      other
   }

   public class Roles
   {
      public static void AddRole(string id, string name)
      {
      }
   }

   public class Shweta
   {
      public void AddUser(string ID, string Name, string Password)
      {
         ///some codes
         SaveSecurity();
      }
      public void DeleteUser(User ObjUser)
      {

      }
      public void AddPermission(string ID, string Name, AccessType Access)
      {

      }
      public void DeletePermission(Permission ObjPermission)
      {

      }
      public void AddRole(string ID, string Name)
      {
         Roles.AddRole(ID, Name);
      }
      public void SaveSecurity()
      {
         ///Saves the data
      }

      public TResult CallMethod<TResult>(Func<TResult> func)
      {
         try
         {
            return func();
         }
         catch (Exception e)
         {
            // Add Handle Exception

            // replace the next line by exception handler
            throw e;
         }
      }

      public void CallMethod(Action method)
      {
         this.CallMethod(() => { method(); return 0; });

         this.SaveSecurity();
      }

      public static void test()
      {
         var s = new Shweta();
         s.CallMethod(() => s.AddRole("theId", "theName"));
         s.CallMethod(() => s.DeleteUser(new User()));
         s.CallMethod(() => s.AddPermission("theId", "theName", AccessType.full));
         s.CallMethod(() => s.DeletePermission(new Permission()));
         s.CallMethod(() => s.AddRole("theId", "theName"));
      }
   }
}

【讨论】:

  • 我喜欢这个想法,但是什么阻止我调用 DeleteUser,因为它是一个公共方法?看起来 DeleteUser 不会调用 SaveSecurity。
猜你喜欢
  • 2012-08-04
  • 2021-04-09
  • 2019-02-01
  • 1970-01-01
  • 2020-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多