传递方法作为参数

时间:2011-10-10 14:28:02

标签: c# delegates

我有一个方法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 个答案:

答案 0 :(得分:10)

怎么样:

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);
    }
}

答案 1 :(得分:7)

更新我对你的问题有点不清楚,如果传入的arg正在方法的其他任何地方使用,它看起来不像,所以你可以选择{{ 1}}并使用lambda指定要使用捕获的参数调用的委托:

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();
    }
}

或者如果它是myObj本身,在这种情况下(已经回答了六个变量)你可以根据他的代码将它传回一个委托。

或者,arg是否与mlaObject不同,你想在代码中也做其他事情,在这种情况下你可以这样做:

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

然后:

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);
    }
}

答案 2 :(得分:5)

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);
    }
}

希望我能正确理解这个问题......

答案 3 :(得分:4)

您的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))

答案 4 :(得分:0)

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位,因为它根本没有在函数中使用。

答案 5 :(得分:0)

  

如果我的要求完全适用于代表。

如果您希望SaveChanges方法执行某些功能,您有两个选项

  • 让它直接执行函数(方法内部的代码,或从方法内部调用第二个方法);或
  • SaveChanges方法的功能作为代理提供。

何时使用这些是您的设计选择,取决于场景,整体解决方案和您的偏好。

第一个

的好处
  • 能够在一个地方看到SaveChanges方法的所有可能结果
  • 对于不了解代表如何工作的人而言,不那么容易混淆

第二个

的好处
  • 能够从SaveChanges方法中排除所有可能的功能(它不需要巨大的caseif else if else if
  • 传递给SaveChanges方法的函数可以在调用堆栈中位于它之上,它不需要知道它们是什么或它们如何工作,它们可以做它不理解的事情,它们可以重复使用 - 在别处调用或在其他函数中用作代理。

我认为第一点是这里的主要观点。如果您只处理几个场景,那么可以使用if else if else if,但如果您获得的选项多于少数并且更喜欢更通用的SaveChanges方法,那么请使用委托的psdd。