比较代表行动<t> </t>

时间:2011-07-14 23:11:04

标签: c# generics delegates comparison

随意质疑我的理智。

我需要确定Action<T> vs 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关键字,我无法进行直接的实例比较。在上面发布的I(第一个)尝试中,我试图让我的回调与添加它的形式相匹配。这是行不通的。我尝试过比较目标,方法,甚至将每种方法转换为其他类型,然后进行比较。

我决定转换我传递的回调,就像它被添加到最后一个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 }

我希望这些额外信息有所帮助。

      • **更新

我发现我让这太复杂了。我需要做的就是添加我的动作,然后从每个字典中删除(唯一的实例)。我正在努力做一些复杂的事情。

目前没有提供任何方法我可以肯定地说,但是我正在标记我认为其他人将使用最佳镜头作为答案。谢谢所有贡献的人。

3 个答案:

答案 0 :(得分:7)

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

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

但请注意,第一行和第二行之间的比较

答案 1 :(得分:2)

这会有用吗?

messageReceivedCallbacks[callbackType].Remove(messageReceivedCallbacks[callbackType].FirstOrDefault(x => x.Target == messageCallback.Target && x.Method == messageCallback.Method));

答案 2 :(得分:0)

要确定两个委托是否相同,您只需要比较方法和目标对象:

var list = messageReceivedCallbacks[callbackType];
for (var i = list.Count-1; i >= 0; i--)
    if (list[i].Method == messageCallback.Method && list[i].Target == messageCallback.Target)
        list.RemoveAt(i);