我有一个提升事件的课程。我希望订阅者能够修改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似乎没有设置值。我做错了吗?
答案 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
}
}
}
}