代码之家  ›  专栏  ›  技术社区  ›  user441521

如何连接具有Action属性的实例方法

c#
  •  0
  • user441521  · 技术社区  · 5 年前

    我有一个给定的类,它将字符串消息“注册”到操作:

    class NetworkCode
        {
            private Dictionary<string, Action<dynamic>> registrations = new Dictionary<string, Action<dynamic>>();
    
            public void Register(string msg, Action<dynamic> action)
            {
                if (registrations.ContainsKey(msg))
                {
                    registrations[msg] += action;
                }
                else
                {
                    registrations.Add(msg, action);
                }
            }
    
            public void OnReceiveMessageTest()
            {
                // simulate the callback from the server
    
                dynamic args = new ExpandoObject();
    
                args.Mana = 10;
                args.Path = new List<Point>
                {
                    new Point { X = 0, Y = 0 },
                    new Point { X = 1, Y = 0 },
                    new Point { X = 1, Y = 1 }
                };
    
                registrations["MOVE_OPPONENT"](args);
            }
        }
    

    我有一个属性:

    [AttributeUsage(AttributeTargets.Method)]
        class NetworkMethodAttribute : Attribute
        {
            public string Message { get; }
            public NetworkMethodAttribute(string msg)
            {
                Message = msg;
            }
        }
    

    然后使用该属性:

    class OpponentTeam
        {
            private int mana = 0;
    
            public OpponentTeam()
            {
    
            }
    
            [NetworkMethod("MOVE_OPPONENT")]
            private void UpdateMana(dynamic args)
            {
                mana = args.Mana;
            }
        }
    

    我自己创建使用此属性的类的实例,并创建NetworkCode类。如何从这些实例中找到具有此属性的实例上的方法,然后通过调用Register()类来注册它们?

    NetworkCode network = new NetworkCode();
    OpponentTeam opponentTeam = new OpponentTeam();
    
    // I want to register with the NetworkCode from the opponentTeam instance that specific method that has the attribute
    
    0 回复  |  直到 5 年前
        1
  •  0
  •   Troy    5 年前

    让我看看我是否理解目标。您要确保 OpponentTeam 可以随时通知 NetworkCode 从服务器接收消息。如果这是正确的,我会选择A选项。

    选项A

    此选项使用 delegate event . This article 详细介绍委托、事件和处理程序方法。

    代表:

    // The delegate defines what method signatures can be attached to an event
    public delegate void NetworkMessageReceivedHandler(string message, dynamic args);
    

    网络代码:

    class NetworkCode
    {
        // The multi-cast event that many instances can attach to and be notified
        public event NetworkMessageReceivedHandler NetworkMessageReceived;
    
        public void OnReceiveMessageTest()
        {
            // simulate the callback from the server
    
            dynamic args = new ExpandoObject();
    
            args.Mana = 10;
            args.Path = new List<Point>
            {
                new Point { X = 0, Y = 0 },
                new Point { X = 1, Y = 0 },
                new Point { X = 1, Y = 1 }
            };
    
            // Check to see if any code has registered for this event
            if (NetworkMessageReceived != null)
            {
                // Assuming "MOVE_OPPONENT" is a message from the server
                NetworkMessageReceived("MOVE_OPPONENT", args);
            }
        }
    }
    

    对立面图

    class OpponentTeam
    {
        private int mana = 0;
    
        // The event handler for each instance
        public void OnNetworkMessageReceived(string message, dynamic args)
        {
            switch (message)
            {
                case "MOVE_OPPONENT": { UpdateMana(args); } break;
                // TODO: Add additional network messages here.
            }
        }
    
        private void UpdateMana(dynamic args)
        {
            mana = args.Mana;
        }
    }
    

    电线向上

    NetworkCode network = new NetworkCode();
    OpponentTeam opponentTeam = new OpponentTeam();
    
    // This registers the opponent instance's handler of the network message received event
    network.NetworkMessageReceived += opponentTeam.OnNetworkMessageReceived;
    

    选项B

    这个选项通过对提供的代码进行最小的更改来更直接地解决这个问题,但并没有达到我认为的目标。

    我对网络代码定义进行了如下调整

    class NetworkCode
    {
        private Dictionary<string, Tuple<OpponentTeam, MethodInfo>> registrations = new Dictionary<string, Tuple<OpponentTeam, MethodInfo>>();
    
        public void Register(string msg, OpponentTeam team, MethodInfo method)
        {
            if (!registrations.ContainsKey(msg))
            {
                registrations[msg] = new Tuple<OpponentTeam, MethodInfo>(team, method);
            }
        }
    
        public void OnReceiveMessageTest()
        {
            // simulate the callback from the server
    
            dynamic args = new ExpandoObject();
    
            args.Mana = 10;
            args.Path = new List<Point>
            {
                new Point { X = 0, Y = 0 },
                new Point { X = 1, Y = 0 },
                new Point { X = 1, Y = 1 }
            };
    
            Tuple<OpponentTeam, MethodInfo> registration = registrations["MOVE_OPPONENT"];
            registration.Item2.Invoke(registration.Item1, new[] { args });
        }
    }
    

    ...然后我这样叫它。。。

    NetworkCode network = new NetworkCode();
    OpponentTeam opponentTeam = new OpponentTeam();
    
    // This gets the first method that defines the NetworkMethodAttribute
    MethodInfo method = opponentTeam.GetType().GetMethods().FirstOrDefault(m => m.GetCustomAttribute<NetworkMethodAttribute>() != null);
    
    // This gets the actual attribute for the method found
    NetworkMethodAttribute attribute = method.GetCustomAttribute<NetworkMethodAttribute>();
    
    // This calls register using the message defined by the attribute, the instance of opponent team, and the method info for invoking the method
    network.Register(attribute.Message, opponentTeam, method);