【问题标题】:How to add a callback to a webform Project如何向 Web 表单项目添加回调
【发布时间】:2015-04-14 13:44:31
【问题描述】:

我想为一个对象的所有方法添加一个通用的回调函数。我找到了this SO question,但在这种方法中,我必须修改类的每个函数。我想定义一些beforeFilter 方法,在每次方法调用之前触发。我知道我可以为此使用Action delegates,但我不知道该怎么做。

更新:例如,我想要的是这样的

Class MyClass

    Sub MyCallback
        'callback code...
    End Sub

    'Rest of tyhe code

End Class

如您所见,理想的做法是在所有其他方法之前添加一个简单(或多个)方法来触发。也许有一些基类或接口,我不知道(这就是我要求的原因)。

我认为可能的其他一些选择是克隆对象并定义一个新类,而不是向现有类添加代码。所以在那Class使用Object通过Type访问方法

Class NewClass

     Sub AddCallback(Obj As Object, Callback As Action)
          'Add the callback here
     End Sub
End Class

我只是在猜测,也许我的某些选择甚至不可行,所以请帮助我解决这个问题

最接近的方法

我现在有的,就是这个方法

Sub RunWithCallback(beforFilter As Action, f As Action)

    beforeFilter()
    f()

End Sub

(这意味着RunWithCallback 有很多重载来管理带有Actions 和Funcs 委托的Sub 和函数,具有不同数量的参数)要使用它,我将不得不运行这个Sub调用任何 Object 方法(传递 ByRef 参数以捕获函数中的返回值)。像这样的

Public Sub DoNothing()
    Debug.WriteLine("Callback working!")
End Sub

Public Sub BeforeFilter()
    Debug.WriteLine("Testing callback...")
End Sub

'To run the above function    
RunWithCallback(AddressOf BeforeFilter, AddressOf DoNothing)

我认为应该有一个更好的解决方案,可以避免调用相同的子,避免重载,对象类的某种动态扩展方法

【问题讨论】:

  • 一些示例代码可能有用。事实上,目前还不清楚你想要什么。例如,beforeFilter 应该在调用方法之前还是在每个方法开始时调用? Action 委托仍然需要重构,所以这似乎不是您想要的。
  • 检查我的编辑,如果您仍有疑问,请再次评论。
  • 如果MyCallbackMyClass 中并从MyClass 调用,为什么类不能调用它(这与“回调”完全不同)。当方法可以访问您希望从其他地方使用的方法时,更常见的是使用委托(不一定是Action)。例如,ClassA.DoFoo 是从 ClassB 调用的,而在 DoFoo 的过程中,您需要它来调用 ClassB.GetBar
  • 我可以访问我想要检查的类,但是那个类有大约 1k 行代码,而且我还有一些其他类似的类,所以在每个方法之前添加一个方法的调用类的不是一个好的选择
  • 对不起,您的问题仍然很混乱。在调用任何/所有其他本地方法之前运行的 beforeFilter 方法示例根本没有真正描述回调。你应该明确what你想做什么,而不是如何,否则你将得到的唯一答案将基于标题并与委托相关。

标签: c# vb.net callback delegates


【解决方案1】:

这是一个示例,代表如何工作以及如何使用它们:

public class MyClass
{
    // MyDelegate callback holder
    private MyDelegate _myDelegate;

    // Singleton holder
    private static volatile MyClass _instance;

    ///<summary>
    /// Instance property
    ///</summary>
    public static MyClass Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new MyClass();
            }
            _instance.MyCallbacks(_instance.MyDelegateCallback, _instance.MyDelegateCallback1);
            return _instance;
        }
    }

    ///<summary>
    /// Instance multi-callback caller
    ///</summary>
    ///<param name="callbacks">calbacks to call</param>
    ///<returns>MyClass</returns>
    public static MyClass Instance(params MyDelegate[] callbacks)
    {
        if (_instance == null)
        {
            _instance = new MyClass();
        }
        _instance.MyCallbacks(callbacks);
        return _instance;
    }

    ///<summary>
    /// MyClass constructor
    ///</summary>
    private MyClass()
    {
        // Define the callback
        MyDelegate = MyDelegateCallback;
    }

    ///<summary>
    /// MyDelegate property, here u can change the callback to any function which matches the structure of MyDelegate 
    ///</summary>
    public MyDelegate MyDelegate
    {
        get
        {
            return _myDelegate;
        }
        set
        {
            _myDelegate = value;
        }
    }

    ///<summary>
    /// Call all given callbacks
    ///</summary>
    ///<param name="callbacks">callbacks u want to call</param>
    public void MyCallbacks(params MyDelegate[] callbacks)
    {
        if (callbacks != null)
        {
            foreach (MyDelegate callback in callbacks)
            {
                if (callback != null)
                {
                    callback.Invoke(null);
                }
            }
        }
    }

    ///<summary>
    /// RunTest, if u call this method the defined callback will be raised
    ///</summary>
    public void RunTest()
    {
        if (_myDelegate != null)
        {
            _myDelegate.Invoke("test");
        }
    }

    ///<summary>
    /// MyDelegateCallback, the callback we want to raise
    ///</summary>
    ///<param name="obj"></param>
    private void MyDelegateCallback(object obj)
    {
        System.Windows.MessageBox.Show("Delegate callback called!");
    }

    ///<summary>
    /// MyDelegateCallback1, the callback we want to raise
    ///</summary>
    ///<param name="obj"></param>
    private void MyDelegateCallback1(object obj)
    {
        System.Windows.MessageBox.Show("Delegate callback (1) called!");
    }
}

///<summary>
/// MyDelegate, the delegate function
///</summary>
///<param name="obj"></param>
public delegate void MyDelegate(object obj);

我更新了我的答案,看看MyCallbacks(params MyDelegate[] callbacks)。它将调用与MyDelegate 的结构匹配的不同回调。
编辑:
添加MyClass.InstanceMyClass.Instance(params MyDelegate[] callbacks)

【讨论】:

  • 在您的回答中,我可以看到您可以处理不同的回调结构,但是如何在其他类方法之前调用这些回调?
  • 我编辑了我的答案,我添加了MyClass.Instance。在“get”方法中,我添加了 MyCallbacks(params MyDelegate[] callbacks) 和 2 个测试回调。在你必须调用一个方法的时候,像MyClass.Instance.MyMethodToCall() 那样调用它,因为你一直在调用MyClass.Instance 你定义的回调将被调用。 - 我认为没有更好的解决方案。 - 除了,您将带有所需回调的MyCallbacks(params MyDelegate[] callbacks) 添加到您当前拥有的每个方法中。
  • 第二次编辑,我添加了额外的MyClass.Instance(params MyDelegate[] callbacks),因此您也可以在需要时调用特殊回调。
  • 我希望,我可以帮助解决这个问题,但是,我从未使用过“Aspect 库”。 - 我发现了一些有趣的东西 here 这可能会对你有所帮助。
  • 嗯,你的方法最接近我的需要,所以我会用这个。感谢您的回答
【解决方案2】:

您是否考虑过使用 Aspect 库?根据您的问题,您似乎真的可以用这种方法解决您的问题。

例如,您可以在此处使用PostSharp library,只需派生OnMethodBoundaryAspect class,并处理四个可用的主要事件:

或另外两个:

  • OnResume
  • OnYield

或其中任何一个。简单的架构是这样的:

int MyMethod(object arg0, int arg1)
{
    OnEntry();
    try
    {
        // YOUR CODE HERE 
        OnSuccess();
        return returnValue;
    }
    catch ( Exception e )
    {
        OnException();
    }
    finally
    {
        OnExit();
    }
}

因此您可以轻松调用Callback 函数(并且您可以在OnSuccess 方法中提取运行时传递的参数:

public override void OnSuccess(MethodExecutionArgs args)
{
    CallBack(GetValueYouNeed(args));
}

PostSharp 的简单版本是一种免费的分发许可证,并且有据可查,因此我强烈建议您研究这种方法。

【讨论】:

  • 看起来很有希望,但它对我不起作用。我继承了提到的类,覆盖了方法OnEntry,什么也没发生……该方法没有自动触发。也许我做错了什么。
  • 我记得,你必须为 PostSharp 添加一个后期构建事件来进行包装
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-28
  • 1970-01-01
  • 2010-10-17
  • 2012-02-18
  • 2020-10-28
  • 2019-04-16
  • 2015-11-26
相关资源
最近更新 更多