比较代表行动<T>

Waf*_*Top 10 c# generics comparison delegates

随意质疑我的理智.

我需要确定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)));
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

我明白我想要做的事情可能是不可能的,但一般来说,我只是做一些不正当的事情或缺乏适当的知识来做这件事,就像我想的那样.提前感谢您提供的任何帮助.

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

比较它们会一直失败.以下3项建议均无效.我相信我可以改变我处理它的方式,并通过传递一个键然后指向单独的列表<key, indexOfAction>然后通过索引删除它来使它成为我需要它的工作方式.但是,我觉得我仍然需要付出很大的努力来解决,所以我将提供更多信息,看看它是否有帮助.

这是清单:

private readonly IDictionary<Type, IList<Action<object>>> messageReceivedCallbacks;
Run Code Online (Sandbox Code Playgroud)

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

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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

请耐心等待,因为我对这些更先进的编码更新.我可以告诉这阻止我因为new关键字而进行直接实例比较.在上面发布的I(第一个)尝试中,我试图让我的回调与添加它的形式相匹配.这是行不通的.我尝试过比较目标,方法,甚至将每种方法转换为其他类型,然后进行比较.

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

var callbackConverted = new Action<object>(m =>
                messageReceivedCallback((TMessage)m));
Run Code Online (Sandbox Code Playgroud)

接下来,我使用立即窗口来获取一些信息(回调是列表中的一个,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 }
Run Code Online (Sandbox Code Playgroud)

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

      • **更新

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

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

Rob*_*Rob 7

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

messageReceivedCallbacks[callbackType].Remove(messageCallback);
Run Code Online (Sandbox Code Playgroud)

如果要比较方法体,可以执行以下操作:

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);
Run Code Online (Sandbox Code Playgroud)

结果:

没有编译器优化感谢RenniePet的评论

action one vs two: False
action one vs three: True
action one vs four: False
Run Code Online (Sandbox Code Playgroud)

使用编译器优化

action one vs two: True
action one vs three: True
action one vs four: False
Run Code Online (Sandbox Code Playgroud)

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