C# 将方法作为参数传递

C# 将方法作为参数传递,c#,delegates,C#,Delegates,我有一个方法SaveChanges(T object),它在我的代码中经常被调用,除了取决于调用该方法的操作之外,在SaveChanges中会调用不同的方法。像这样的 protected void SaveChanges<T>(T mlaObject, SomeFunction(arg)) where T : WebObject { try { this._db.SaveChanges(); } catch (Exception e) {

我有一个方法
SaveChanges(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);
    }
}
受保护的void SaveChanges(T mlaObject,SomeFunction(arg))
其中T:WebObject
{
试试{this._db.SaveChanges();}
捕获(例外e)
{
Console.WriteLine(“错误:+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
SaveChanges(article,article.Authors.Remove(person))//person是MlaPerson类型的对象
//或
SaveChanges(article,article.RelatedTags.Remove(tag))//tag是tag类型的对象
//或
SaveChanges(article,article.RelatedWebObjects.Remove(location))//location是MlaLocation类型的对象
我已经阅读了委托方法,但对于如何用我的需求实现它,或者我的需求是否值得委托使用,我有点困惑

编辑:还有,是否可以传递多个操作?

如何:

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);
    }
}
现在,再次阅读您的问题,我认为传递
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);
    }
}
//this.SaveChanges(
//()=>article.Authors.Remove(author),
//()=>article.RelatedTags.Remove(tag));
受保护的void SaveChanges(参数操作[]回滚)
{
试试{this._db.SaveChanges();}
捕获(例外e)
{
Console.WriteLine(“错误:+e”);
foreach(回滚中的var rollback)rollback();
}
}
//重载以支持带有参数的回滚
//这是保存更改(
//作者,
//文章作者:删除,
//authorCache.Remove);
受保护的void SaveChanges(T参数,参数操作[]回滚)
{
试试{this._db.SaveChanges();}
捕获(例外e)
{
Console.WriteLine(“错误:+e”);
foreach(回滚中的var rollback)rollback(arg);
}
}

更新我对您的问题有点不清楚,如果传入的arg正在方法中的其他任何地方使用,它看起来不像,因此您只需执行
操作
并使用lambda指定要使用捕获的参数调用的委托:

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不同,您是否希望在代码中对其执行其他操作,在这种情况下,您可以执行以下操作:

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);
    }
}
protectedvoid SaveChanges(T mlaObject,Action Action,U arg)
其中T:WebObject
{
试试{this._db.SaveChanges();}
捕获(例外e)
{
Console.WriteLine(“错误:+e”);
动作(arg);
}
}

希望我正确理解了问题…

您的
SaveChanges
方法如下所示:

protected void SaveChanges<T,TArg>(T mlaObject, TArg arg, Action<T,TArg> someFunction)
    where T : WebObject
{
   ...
}
受保护的void SaveChanges(T mlaObject、target arg、Action someFunction)
其中T:WebObject
{
...
}
被称为:

this.SaveChanges(myObj, x => article.Authors.Remove(x));
SaveChanges<MlaArticle,Person>(article,person, (article,person) =>  article.Authors.Remove(person))
SaveChanges(article,person,(article,person)=>article.Authors.Remove(person))
我省略了WebObject位,因为它根本没有在函数中使用

如果我的要求保证代表可以使用

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

  • 让它直接执行函数(在方法内部编写代码,或从方法内部调用第二个方法);或
  • 将函数作为委托提供给
    SaveChanges
    方法
何时使用这两个选项是由您决定的设计选择,取决于场景、总体解决方案和您的偏好

第一个的好处

  • 能够在一个位置查看
    SaveChanges
    方法的所有可能结果
  • 对于不知道代理如何工作的人来说,不那么令人困惑
第二条的好处

  • 能够从
    SaveChanges
    方法中排除所有可能的函数(它不需要大量的
    案例
    if-else if
  • 传递给
    SaveChanges
    方法的函数可以在调用堆栈中位于它的上方,它不需要知道它们是什么或它们是如何工作的,它们可以做它不理解的事情,并且它们可以重用-在别处调用或在其他函数中用作委托

我认为第一点是这里的重点。如果您只处理几个场景,那么可以使用
If-else If-else If
,但是如果您有更多的选项,并且更喜欢更通用的
SaveChanges
方法,那么请psdd该委托。

您需要添加arg参数。我喜欢这个,非常简单。可以发送多个操作吗?当然,您可以使用IEnumerable,或者您的操作本身可以指定要调用的任意数量的东西,比如x=>{doA(x);doB(x);doC(x);}@GeorgeDuckett:谢谢,我直觉认为它是
mlaObject
。但第二次读取时可能不是这样。@bflemi3:添加了对多个操作的支持,删除了未使用的
mlaObject
。是的,您做对了。有可能发送多个操作吗?我希望在没有源代码或文档的情况下使用这些代码;-)。嗯,理想情况下,至少你会对它有一些好的///评论。Action/Func委托很快就会成为第二天性,尤其是当你开始使用LINQ时。这段代码真的没有那么糟糕。它可能会使用比简单记事本应用程序更复杂的东西,但实际问题将使用该语言的许多功能。这是非常简洁和不言自明的。你看过最近的一些C或C++代码吗?我唯一的问题就是这个代码是什么?也许对@JamesMichaelHare来说不是问题,bu
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);
    }
}
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))
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));