在C#中使用Tag Message
在C#中模拟Erlang里的Tag Message很简单,其实就是把每条消息封装为Tag和参数列表的形式。同样的,我们使用的都是弱类型的数据——也就是object类型。如下:
public class Message
{
public object Tag { get; private set; }
public ReadOnlyCollection<object> Arguments { get; private set; }
public Message(object tag, params object[] arguments)
{
this.Tag = tag;
this.Arguments = new ReadOnlyCollection<object>(arguments);
}
}
我们可以使用这种方式来实现一个乒乓测试。既然是Tag Message,那么定义一些Tag便是首要任务。Tag表示“做什么”,即消息的“功能”。在乒乓测试中,有两种消息,共三个“含义”。Erlang使用原子作为tag,在.NET中我们自然可以使用枚举:
public enum PingMsg
{
Finished,
Ping
}
public enum PongMsg
{
Pong
}
在这里,我们使用简单的ActorLite进行演示(请参考ActorLite的使用方式)。因此,Ping和Pong均继承于Actor<Message>类,并实现其Receive方法。
对于Ping对象来说,它会维护一个计数器。每当收到PongMsg.Pong消息后,会将计数器减1。如果计数器为0,则回复一条PingMsg.Finished消息,否则就回复一个PingMsg.Ping:
public class Ping : Actor<Message>
{
private int m_count;
public Ping(int count)
{
this.m_count = count;
}
public void Start(Actor<Message> pong)
{
pong.Post(new Message(PingMsg.Ping, this));
}
protected override void Receive(Message message)
{
if (message.Tag.Equals(PongMsg.Pong))
{
Console.WriteLine("Ping received pong");
var pong = message.Arguments[0] as Actor<Message>;
if (--this.m_count > 0)
{
pong.Post(new Message(PingMsg.Ping, this));
}
else
{
pong.Post(new Message(PingMsg.Finished));
this.Exit();
}
}
}
}
对于Pong对象来说,如果接受到PingMsg.Ping消息,则回复一个PongMsg.Pong。如果接受的消息为PingMsg.Finished,便立即退出:
public class Pong : Actor<Message>
{
protected override void Receive(Message message)
{
if (message.Tag.Equals(PingMsg.Ping))
{
Console.WriteLine("Pong received ping");
var ping = message.Arguments[0] as Actor<Message>;
ping.Post(new Message(PongMsg.Pong, this));
}
else if (message.Tag.Equals(PingMsg.Finished))
{
Console.WriteLine("Finished");
this.Exit();
}
}
}
启动乒乓测试:
new Ping(5).Start(new Pong());
结果如下:
Pong received ping
Ping received pong
Pong received ping
Ping received pong
Pong received ping
Ping received pong
Pong received ping
Ping received pong
Pong received ping
Ping received pong
Finished