Передача метода в качестве аргумента - PullRequest
8 голосов
/ 10 октября 2011

У меня есть метод SaveChanges<T>(T object), который часто вызывается в моем коде, за исключением того, что в зависимости от действия, вызывающего метод, в SaveChanges будет вызываться другой метод.Примерно так ...

protected void SaveChanges<T>(T mlaObject, SomeFunction(arg))
    where T : WebObject
{
    try { this._db.SaveChanges(); }
    catch (Exception e)
    {
        Console.WriteLine("Error: " + e);
        SomeFunction(arg);
    }
}

Примеры использования:

SaveChanges<MlaArticle>(article, article.Authors.Remove(person)) //person is an object of type MlaPerson
//OR
SaveChanges<MlaArticle>(article, article.RelatedTags.Remove(tag)) //tag is an object of type Tag
//OR
SaveChanges<MlaArticle>(article, article.RelatedWebObjects.Remove(location)) //location is an object of type MlaLocation

Я прочитал о методах делегатов, но меня немного смущает вопрос о том, как реализовать это с моимитребования или если мои требования требуют использования для делегатов вообще.

РЕДАКТИРОВАТЬ: Кроме того, будет ли возможно передать несколько действий?

Ответы [ 6 ]

10 голосов
/ 10 октября 2011

Как насчет:

protected void SaveChanges<T>(T mlaObject, Action<T> rollback)
    where T : WebObject
{
    try { this._db.SaveChanges(); }
    catch (Exception e)
    {
        Console.WriteLine("Error: " + e);
        rollback(mlaObject);
    }
}

Называется как:

this.SaveChanges(myObj, x => article.Authors.Remove(x));

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

// this.SaveChanges(
//     () => article.Authors.Remove(author),
//     () => article.RelatedTags.Remove(tag));
protected void SaveChanges(params Action[] rollbacks)
{
    try { this._db.SaveChanges(); }
    catch (Exception e)
    {
        Console.WriteLine("Error: " + e);
        foreach (var rollback in rollbacks) rollback();
    }
}

// Overload to support rollback with an argument
// this.SaveChanges(
//     author,
//     article.Authors.Remove,
//     authorCache.Remove);
protected void SaveChanges<T>(T arg, params Action<T>[] rollbacks)
{
    try { this._db.SaveChanges(); }
    catch (Exception e)
    {
        Console.WriteLine("Error: " + e);
        foreach (var rollback in rollbacks) rollback(arg);
    }
}
7 голосов
/ 10 октября 2011

ОБНОВЛЕНИЕ Мне было немного неясно из вашего вопроса, используется ли переданный аргумент где-либо еще в методе, он не выглядит так, как вы, поэтому вы можете просто взять Action и используйте лямбду, чтобы указать делегата для вызова с захваченным аргументом:

protected void SaveChanges<T, TArg>(T mlaObject, TArg arg, Action undoFunction)
    where T : WebObject
{
    try { this._db.SaveChanges(); }
    catch (Exception e)
    {
        Console.WriteLine("Error: " + e);
        undoFunction();
    }
}

К которым вы можете перейти:

SaveChanges(article, () => article.Authors.Remove(person));

Или, если это сам myObj, то в этом случае (как уже было указано в шести переменных) вы можете просто передать его обратно в делегат согласно его коду.

Или, отличается ли arg от mlaObject, и вы хотите сделать с ним и другие вещи в коде, в этом случае вы можете сделать:

protected void SaveChanges<T, TArg>(T mlaObject, TArg arg, Action undoFunction)
    where T : WebObject
{
    try { this._db.SaveChanges(); }
    catch (Exception e)
    {
        Console.WriteLine("Error: " + e);
        undoFunction(arg);
    }
}

А затем: 1015 *

SaveChanges(article, person, article.Authors.Remove);
5 голосов
/ 10 октября 2011
protected void SaveChanges<T,U>(T mlaObject, Action<U> action, U arg)
    where T : WebObject
{
    try { this._db.SaveChanges(); }
    catch (Exception e)
    {
        Console.WriteLine("Error: " + e);
        action(arg);
    }
}

Надеюсь, я правильно понял вопрос ...

4 голосов
/ 10 октября 2011

Ваш SaveChanges метод будет выглядеть примерно так:

protected void SaveChanges<T,TArg>(T mlaObject, TArg arg, Action<T,TArg> someFunction)
    where T : WebObject
{
   ...
}

Вызывается как:

SaveChanges<MlaArticle,Person>(article,person, (article,person) =>  article.Authors.Remove(person))
0 голосов
/ 10 октября 2011

если мои требования позволяют использовать делегатов вообще.

Если вы хотите, чтобы метод SaveChanges выполнял какую-либо функцию, у вас есть две опции

  • пусть он выполняет функцию напрямую (код внутри метода или вызов некоторого второго метода изнутри метода); или
  • предоставляет функцию для метода SaveChanges в качестве делегата.

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

Преимущества первого

  • Возможность увидеть все возможные результаты метода SaveChanges в одном месте
  • Менее запутанно для тех, кто не знает, как работают делегаты

Преимущества второго

  • Возможность исключить все возможные функции из метода SaveChanges (для этого не требуется огромных case или if else if else if)
  • Функции, которые передаются методу SaveChanges, могут находиться над ним в стеке вызовов, ему не нужно знать, что они есть или как они работают, они могут делать вещи, которых он не понимает, и они может использоваться повторно - вызываться в другом месте или использоваться в качестве делегатов в других функциях.

Я думаю, что первый пункт здесь главный. Если вы обрабатываете только несколько сценариев, тогда вполне нормально иметь if else if else if, но если вы получаете больше, чем несколько вариантов и предпочитаете более общий метод SaveChanges, тогда psdd этого делегата.

0 голосов
/ 10 октября 2011
protected void SaveChanges<T>(T mlaObject, Action<T> functionToCall)
{
    try { this._db.SaveChanges(); }
    catch (Exception e)
    {
        Console.WriteLine("Error: " + e);
        functionToCall(mlaObject);
    } 
}

Вызовите так:

SaveChanges(actualArticle, article => article.Authors.Remove(person));

Я пропустил бит WebObject, поскольку он вообще не использовался в функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...