似乎无法通过参考传递EventArgs

时间:2016-06-09 13:32:28

标签: c# vb.net events eventhandler eventargs

我有一个提升事件的课程。我希望订阅者能够修改EventArgs中传递的值。

在提升事件的班级中:

    class Factory
    {
    public event EventHandler<MessageReceivedEventArgs> MessageReceived;

    private IServerLib _myObject;

    public void Connect()
    {
        _myObject = new ServerLib();
        _myObject.AddMessageReceivedHandler((short terminal, ref string message, ref short functionNo) =>
        {
            MessageReceivedEventArgs args = new MessageReceivedEventArgs { Terminal = terminal, Message = message, FunctionNo = functionNo };
            MessageReceivedEvent(ref args);
        });
    }

    private void MessageReceivedEvent(ref MessageReceivedEventArgs args)
    {
        EventHandler<MessageReceivedEventArgs> handler = MessageReceived;
        if (handler != null)
        {
            handler(this, args);
        }
    }

    public class MessageReceivedEventArgs : EventArgs
    {
        public short Terminal { get; set; }
        public string Message { get; set; }
        public short FunctionNo { get; set; }
    }
}


interface IServerLib
    {
        void AddMessageReceivedHandler(MessageReceivedEventHandler action);
    }
    public delegate void MessageReceivedEventHandler(short terminal, ref string message, ref short functionNo);

订阅者(恰好是VB)如下所示:

Dim WithEvents _va As MyAssembly.MyClass

Private Sub _va_MessageReceived(sender As Object, e As Factory.MessageReceivedEventArgs) Handles _va.MessageReceived
    Debug.WriteLine($"Message: {e.Message} Terminal: {e.Terminal} Function: {e.FunctionNo}")
    If e.Message = "1" Then
        e.Message = ""
        e.FunctionNo = 0
        Debug.WriteLine("Cancelled")
    End If
End Sub

这会引发事件,但设置e.Message和e.Function似乎没有设置值。我做错了吗?

3 个答案:

答案 0 :(得分:2)

问题在于使用这一行:

var args = new MessageReceivedEventArgs
           { Terminal = terminal, Message = message, FunctionNo = functionNo };

它将所有变量复制到事件args类。更改它不会在另一端(您添加ref的位置)自动更改它。这不是一个很好的解决方案,但要向您证明这是问题,请在handler(this, args)之后添加:

message = args.Message;
functionNo = args.FunctionNo;

这将导致ref s覆盖这些值。

答案 1 :(得分:1)

看来你认为你的&#34; ref&#34;参数应受上述代码的影响,但事实并非如此。是的,您通过message功能引用MessageReceivedEvent,但随后将其分配给MessageReceivedEventArgs.Message,这是按值而不是通过引用发生的。

结果,当您在VB代码中修改MessageReceivedEventArgs.Message时,message变量不会受到影响(但MessageReceivedEventArgs.Message 当然受到影响),尽管如此你通过引用传递它,因为它应该是。

你应该做的是将MessageReceivedEventArgs的实例直接传递给你的函数(不在该函数中创建):

private void MessageReceivedEvent(MessageReceivedEventArgs args)
{
    EventHandler<MessageReceivedEventArgs> handler = MessageReceived;
    if (handler != null)
    {
        handler(this, args);
    }
}

答案 2 :(得分:0)

首先,您不需要ref才能更改MessageReceivedEventArgs的属性。对象变量只是指向内存中实际对象的指针,因此您已经在更改其属性。如果您需要订户更改引用本身 - 即将指针重置为另一个对象 - 那么您需要使用ref。 其次,这种设计很糟糕,因此我不确定我是否理解这个问题。无论如何,我将提供一种正确的方法来提升事件并在此之后消耗更改的值。

class Factory 
{
    public event EventHandler<MessagereceivedEventArgs> MessageReceived;

    void ReceiveMessage(string Message)
    {
        // Do something with the Message

        // Then let your subscribers know that the message has been processed:
        if (MessageReceived != null)
        {
            var ea = new MessageReceivedEventArgs();
            ea.Message = Message;
            // Set ea properties as appropriate 
            MessageReceived(this, ea);
            // Check ea properties for change
            if (ea.Message != Message)
            {
                // A subscriber has changed the message in the MessageReceivedEventArgs
            }
        }
    }
}