Как вызвать метод неявно после вызова каждого метода?

Извините за потрясающий титул для публикации. Мне немного любопытно узнать, есть ли в решении проблемы какие-либо решения или нет. Ситуация заключается в том, что у меня есть функция под названием 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() после окончания функции. Мой вопрос:

Есть ли способ вызвать эту функцию после каждой функции, не выписывая одну и ту же строку снова и снова?

Моя диаграмма классов выглядит следующим образом

введите описание изображения здесь

Ответ 1

Вам нужно изучить шаблон репозитория,

Отделяйте свои классы и операции,

Создайте еще один слой (назовите его бизнес-слоем) или все, что будет вызывать разные методы разных классов...

Банкомат, который вы пытаетесь использовать OOP, но все, что вы делаете, - это функциональное программирование.

Реализация шаблонов репозитория и единицы работы в приложении ASP.NET MVC

Изменить После добавления диаграммы классов

Ваши классы коллекции на самом деле представляют собой класс репозитория, вам нужно будет перемещать ваши методы, такие как 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);
}

Выше только добавление слоя, чтобы ваш код выглядел более читаемым и будущим доказательством за очень короткое время, но если у вас есть больше времени для инвестиций, вы можете также просмотреть шаблон Observer...

Внедрить шаблон Observer в С#

Каждый раз, когда ваш объект изменяется, вы можете вызвать метод SaveSecurity (который будет находиться в другом классе (возможно, это имя изменится). Если вы не хотите вызывать SaveSecurity для каждой смены объекта, вы можете добавить свойство для вашего объекта, например IsSecurityChanged? Если да, то вызовите SaveSecurity.

Больше, чтобы объяснить, но если вы посмотрите на шаблон Observer выше, вы получите представление.

Еще один способ, но я лично не рекомендую использовать интерфейс IDisposable, а затем в методе dispose вызывается метод SaveSecurity для объекта. НО НЕ РЕКОМЕНДУЕТСЯ МЕНЯ.

Ответ 2

Только с С# вы не можете, но есть некоторые решения, которые могут помочь.

Лучшее, что я знаю, PostSharp. Это даст вам возможность определять действия до и после вызова метода (например). Некоторую информацию о нем можно найти здесь и здесь.

Единственное, что вам нужно сделать, это украсить методы, которые вы хотите вызвать SaveSecurity для атрибута.

Если вы не хотите использовать такие инструменты, просто сохраните их как есть. Это нормально, как есть.

Ответ 3

Вы можете использовать какое-то Аспектно-ориентированное программирование (не знаете, как это сделать на С#, но попробуйте поработать с ним).

Другой способ, который не лучше, чем просто вызвать одну функцию в конце другого, будет создавать вспомогательную функцию с функциональным параметром, который выполняет свой параметр, а затем вызывает вашу функцию безопасности. Но тогда тело каждой функции будет выглядеть примерно так (если я правильно помню С# лямбда):

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

Таким образом, он будет содержать что-то дополнительное, как ваше оригинальное решение.

Кстати, может быть, вам нужно больше в вашем звонке. Если вы хотите, чтобы эта функция вызывалась даже в случае возникновения исключения, вам нужно

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

и скрытие этого в функциональном помощнике имеет смысл.

Ответ 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"));
      }
   }
}