我已经大大减少了我项目中的代码,所以它是复制和可管理的,但是如果你想在一个控制台项目中进行调试,它将需要nuget包:Install-Package MsgPack.Cli。
好的,下面我评论了问题这一行,我想知道的是为什么列表在_outgoingMessageQueue队列中强制重复。这是某种被捕获的变量难题吗?请尽可能详细地提供
using MsgPack.Serialization;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Collections;
namespace QueueTest
{
public class Message
{
public string Data { get; set; }
}
public class InternalFactoryMsg<T>
{
public T Data { get; set; }
public string Group { get; set; }
public List<byte[]> ReturnIds { get; set; }
}
public class FactoryHelpers
{
public static List<byte[]> GetReturnIdentities(List<byte[]> messageBytes, byte[] identity)
{
var response = new List<byte[]>();
foreach (byte[] part in messageBytes)
{
if (part != null && part.Length > 0)
response.Add(part);
else
break;
}
// may not need this with good routing, but can avoid errors
if (messageBytes.Count > 0 && messageBytes[0] == identity)
{
messageBytes.RemoveAt(0);
Console.WriteLine("[GetReturnIdentities]: Removed identity from start, check your routing!");
}
// no return identities, send empty list as these bytes will be the
// app message and command identity couple
if (response.Count == messageBytes.Count)
return new List<byte[]>();
return response;
}
public static byte[] SerializeData<T>(T appMsg)
{
var serializer = MessagePackSerializer.Get<T>();
using (var byteStream = new MemoryStream())
{
serializer.Pack(byteStream, appMsg);
return byteStream.ToArray();
}
}
public static T DeserializeData<T>(byte[] bytes)
{
try
{
var serializer = MessagePackSerializer.Get<T>();
using (var byteStream = new MemoryStream(bytes))
{
return serializer.Unpack(byteStream);
}
}
catch (Exception ex)
{
return default(T);
}
}
}
public class Factory: FactoryHelpers
{
protected ConcurrentQueue<KeyValuePair<string, List<byte[]>>> _outgoingMessageQueue { get; set; }
public ConcurrentQueue<KeyValuePair<string, List<byte[]>>> IncomingMessageQueue { get; set; }
public Factory()
{
_outgoingMessageQueue = new ConcurrentQueue<KeyValuePair<string, List<byte[]>>>();
IncomingMessageQueue = new ConcurrentQueue<KeyValuePair<string, List<byte[]>>>();
// add fake incoming message
var byteMsg = new List<byte[]>()
{
Encoding.Unicode.GetBytes("socket1"),
Encoding.Unicode.GetBytes(""),
Encoding.Unicode.GetBytes("data")
};
var msg = new KeyValuePair<string, List<byte[]>>("socket1", byteMsg);
IncomingMessageQueue.Enqueue(msg);
}
public void AddMessage<T>(InternalFactoryMsg<T> msg)
{
var msgBytes = msg.ReturnIds ?? new List<byte[]>();
msgBytes.Add(new byte[0]);
msgBytes.Add(Factory.SerializeData<T>(msg.Data));
_outgoingMessageQueue.Enqueue(new KeyValuePair<string, List<byte[]>>("socket2", msgBytes));
}
public List<KeyValuePair<string, List<byte[]>>> GetQueue()
{
return _outgoingMessageQueue.ToList();
}
public static T GetDataFromBytes<T>(List<byte[]> msgBytes)
{
// ignoring null checks etc
return DeserializeData<T>(msgBytes.Last());
}
}
public static class MessageLayer
{
public static Factory Factory = new Factory();
public static void Init()
{
Task.Factory.StartNew(u =>
{
while(true)
{
KeyValuePair<string, List<byte[]>> msg;
if(Factory.IncomingMessageQueue.TryDequeue(out msg))
{
var data = msg.Value.Last();
var returnIds = Factory.GetReturnIdentities(msg.Value, Encoding.Unicode.GetBytes(msg.Key));
IncomingCommands.HandleDataCommand(data, "test grp", returnIds);
}
// nice and slow for simulation
Thread.Sleep(400);
}
}, TaskCreationOptions.LongRunning);
}
public static void SendMessage(Message msg, string group, List<byte[]> returnIds)
{
var intMsg = new InternalFactoryMsg<Message>();
intMsg.Data = msg;
intMsg.Group = group;
intMsg.ReturnIds = returnIds;
Factory.AddMessage<Message>(intMsg);
}
}
public static class DataAccessor
{
public static List<Message> GetData(byte[] data)
{
return new List<Message>()
{
new Message() { Data = "magic" },
new Message() { Data = "data!" }
};
}
}
public static class IncomingCommands
{
public static void HandleDataCommand(byte[] data, string group, List<byte[]> returnIds)
{
List<Message> result;
// does big switch, gets data response
result = DataAccessor.GetData(data);
foreach (Message msg in result)
{
var local = msg;
var fix = new List<byte[]>(returnIds);
// THIS IS THE ISSUE
// comment out the following line and uncomment the one below to fix it
// but... why??? :O !!!
MessageLayer.SendMessage(local, group, returnIds);
//MessageLayer.SendMessage(local, group, fix);
}
// check the queue
Console.WriteLine("---------------------------");
Console.WriteLine("::Checking queue contents::");
var msgs = MessageLayer.Factory.GetQueue();
foreach(var m in msgs)
{
var check = Factory.GetDataFromBytes<Message>(m.Value);
Console.WriteLine("data -> " + check.Data);
}
}
}
public class Program
{
static void Main(string[] args)
{
MessageLayer.Init();
while(true)
{
Thread.Sleep(400);
}
}
}
}
如果你无法解决问题,请投票以获得关注。感谢
答案 0 :(得分:1)
原因是
var msgBytes = msg.ReturnIds ?? new List<byte[]>();
导致变量捕获,这意味着后续使用强制重复引用同一个对象