c# - 比较委托(delegate) Action<T>

标签 c# generics delegates comparison

请随意质疑我的理智。

我需要确定一个 Action<T>对比Action<T>是原始实例。我拥有的是一个带有类变量的类 protected Action<T> MessageCallback = null;当我的abstract class Message<T>是通过抽象方法创建的,我强制“他们”初始化 MessageCallBack。此 MessageCallback 被添加到 IList<Action<object>> .此列表中定义的每个操作都可以不同。现在,我想要做的是从列表中删除一个特定的操作,但我尝试比较它时失败了。

以下是我最后一次尝试设置的示例:

public void Unsubscribe<TMessage>(Action<TMessage> messageCallback)
    {
        var messageType = typeof(TMessage);

        var callbackTypes = messageReceivedCallbacks
            .Keys
            .Where(k => k.IsAssignableFrom(messageType));

        lock (messageReceivedCallbacks)
        {
            foreach (var callbackType in callbackTypes)
            {
                messageReceivedCallbacks[callbackType].Remove(new Action<object>(m => 
                    messageCallback((TMessage)m)));
            }
        }
    }

我知道我想做的事情可能无法实现,但通常我只是以不正确的方式做某事或缺乏适当的知识来按照我的设想去做。提前感谢您提供的任何帮助。

      • 尝试以下一些方法后更新:

比较它们总是失败。以下目前的 3 条建议均无效。我确实相信我可以改变我处理这个问题的方式,并通过传入一个带有操作的键来让它按照我需要的方式工作,然后指向单独的列表 <key, indexOfAction>然后按索引删除它。但是,我觉得我仍然需要付出很大的努力才能解决,所以我将提供更多信息以查看是否有帮助。

这是列表:

private readonly IDictionary<Type, IList<Action<object>>> messageReceivedCallbacks;

以下是将操作添加到列表的方式:

void AddMessageReceivedCallback<TMessage>(Action<TMessage> messageReceivedCallback)
    {
        var intermediateReceivedCallback = new Action<object>(m => 
            messageReceivedCallback((TMessage)m));

        var receivedList = messageReceivedCallbacks.GetOrCreateValue(typeof(TMessage),
            () => new List<Action<object>>());
        lock (receivedList)
        {
            receivedList.Add(intermediateReceivedCallback);
        }
    }

请耐心等待,因为我对其中一些更高级的编码还很陌生。我可以看出这会阻止我进行直接实例比较,因为 new关键词。在我(第一次)在上面发布的尝试中,我试图让我的回调与添加它的形式相匹配。这是行不通的。我试过比较目标、方法,甚至将它们转换为其他类型,然后再进行比较。

我决定转换我传递的回调,就像它被添加到最后一个 aka 一​​样:

var callbackConverted = new Action<object>(m =>
                messageReceivedCallback((TMessage)m));

接下来,我使用立即窗口来获取一些信息(回调是列表中的那个,callbackConverted 是我传入的那个):

callback.Target
{MessageBus.MessageCoordinator.<Tests.MessageBus.TestMessage>}
    messageReceivedCallback: {Method = {Void <InitializeMessageCallback>b__0(Tests.MessageBus.TestMessage)}}

callback.Method
{Void <AddMessageReceivedCallback>b__8(System.Object)}
    [System.Reflection.RuntimeMethodInfo]: {Void <AddMessageReceivedCallback>b__8(System.Object)}
    base {System.Reflection.MethodBase}: {Void <AddMessageReceivedCallback>b__8(System.Object)}
    MemberType: Method
    ReturnParameter: {Void }
    ReturnType: {Name = "Void" FullName = "System.Void"}
    ReturnTypeCustomAttributes: {Void }


callbackConverted.Target
{MessageBus.MessageCoordinator.<Tests.MessageBus.TestMessage>}
    messageReceivedCallback: {Method = {Void <InitializeMessageCallback>b__0(Tests.MessageBus.TestMessage)}}
    messageType: {Name = "TestMessage" FullName = "Tests.MessageBus.TestMessage"}

callbackConverted.Method
    {Void <Unsubscribe>b__1d(System.Object)}
        [System.Reflection.RuntimeMethodInfo]: {Void <Unsubscribe>b__1d(System.Object)}
        base {System.Reflection.MethodBase}: {Void <Unsubscribe>b__1d(System.Object)}
        MemberType: Method
        ReturnParameter: {Void }
        ReturnType: {Name = "Void" FullName = "System.Void"}
        ReturnTypeCustomAttributes: {Void }

我希望这些附加信息对您有所帮助。

      • **更新

我发现我把它弄得太复杂了。我需要做的就是添加我的操作,然后从每个字典中删除(它的唯一实例)。我正竭尽全力去做一些复杂的事情。

目前没有提供我可以肯定地说有效的方法,但我标记了我认为其他人最有可能用作答案的方法。感谢所有贡献者。

最佳答案

您是在谈论寻找执行相同操作或完全相同实例的操作吗? 如果它是完全相同的实例,您可以使用:

messageReceivedCallbacks[callbackType].Remove(messageCallback);

如果你想比较方法体,你可以这样做:

private bool ActionComparer<T>(Action<T> firstAction, Action<T> secondAction)
{
    if(firstAction.Target != secondAction.Target)
        return false;

    var firstMethodBody = firstAction.Method.GetMethodBody().GetILAsByteArray();
    var secondMethodBody = secondAction.Method.GetMethodBody().GetILAsByteArray();

    if(firstMethodBody.Length != secondMethodBody.Length)
        return false;

    for(var i = 0; i < firstMethodBody.Length; i++)
    {
        if(firstMethodBody[i] != secondMethodBody[i])
            return false;
    }
    return true;
}

Action<bool> actionOne = (param1) => {return;};
Action<bool> actionTwo = (param2) => {var i = 1; return;};
Action<bool> actionThree = (param1) => {return;};
Action<bool> actionFour = (param2) => {Thread.Sleep(1); return;};

var areEqualOneTwo = ActionComparer(actionOne, actionTwo);
var areEqualOneThree = ActionComparer(actionOne, actionThree);
var areEqualOneFour = ActionComparer(actionOne, actionFour);

Console.WriteLine("action one vs two: " + areEqualOneTwo);
Console.WriteLine("action one vs three: " + areEqualOneThree);
Console.WriteLine("action one vs four: " + areEqualOneFour);

结果:

没有编译器优化感谢 RenniePet's comment

action one vs two: False
action one vs three: True
action one vs four: False

编译器优化

action one vs two: True
action one vs three: True
action one vs four: False

但是请注意, Action 一和 Action 二的比较

关于c# - 比较委托(delegate) Action<T>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6701041/

相关文章:

c# - 移植 C# 代码以在 OSX 上运行

c# - 来自带时区的SQL Server中的DateTime

java - Generics Java,无限通配符

ios - 如何使用协议(protocol)/委托(delegate)在 UIViewController 之间传递数据

iphone - 使用协议(protocol)和委托(delegate)在 View Controller 之间传递数据

delegates - 如何在 C++/CLI 中使用 boost::bind 绑定(bind)托管类的成员

c# - 视频不使用统一在 Visual Studio 的本地机器上播放

java - 在其他类中实例泛型类

c# - 更新泛型类的泛型属性?

c# - Magick.NET 减少 gif 文件大小