给定Queue<MyMessage>
,其中MyMessage
是某些类型消息的基类:所有消息类型都有不同的字段,因此它们将使用不同的字节数。因此,根据字节而不是队列中存在的元素来测量此队列的填充级别是有意义的。
实际上,由于此队列与连接相关联,因此我可以更好地控制消息流,如果队列几乎已满,则可以减少流量。
为了获得这个目标,我想用自定义类Queue
包装一个简单的MyQueue
。
public class MyQueue
{
private Queue<MyMessage> _outputQueue;
private Int32 _byteCapacity;
private Int32 _currentSize; // number of used bytes
public MyQueue(int byteCapacity)
{
this._outputQueue = new Queue<MyMessage>();
this._byteCapacity = byteCapacity;
this._currentSize = 0;
}
public void Enqueue(MyMessage msg)
{
this._outputQueue.Enqueue(msg);
this._currentSize += Marshal.SizeOf(msg.GetType());
}
public MyMessage Dequeue()
{
MyMessage result = this._outputQueue.Dequeue();
this._currentSize -= Marshal.SizeOf(result.GetType());
return result;
}
}
问题是这对于类不好,因为Marshal.SizeOf
会引发ArgumentException
异常。
UPDATE:作为替代解决方案,我可以在每种消息类型上添加方法int SizeBytes()
,但这个解决方案看起来有点难看,尽管它可能是最有效的,因为您无法轻松测量参考类型。
public interface MyMessage
{
Guid Identifier
{
get;
set;
}
int SizeBytes();
}
实现此接口的类除了实现SizeBytes()
方法外,还必须实现Identifier
属性。
public class ExampleMessage
{
public Guid Identifier { get; set; } // so I have a field and its Identifier property
public String Request { get; set; }
public int SizeBytes()
{
return (Marshal.SizeOf(Identifier)); // return 16
}
}
sizeof
运算符不能与Guid
一起使用,因为它没有预定义的大小,因此我使用Marshal.SizeOf()
。但在这一点上,或许我应该使用实验确定的值:例如,因为Marshal.SizeOf()
为Guid
返回16,并且string
由N char
组成,那么SizeBytes()
方法可以如下:
public int SizeBytes()
{
return (16 + Request.Length * sizeof(char));
}
答案 0 :(得分:6)
如果您可以使用虚方法SizeOf()编辑MyMessage基类,那么您可以让消息类在其基本类型上使用c#sizeof
运算符。 如果你可以这样做,你的其余代码就是黄金。
答案 1 :(得分:0)
您可以通过测量二进制序列化的长度来获得对象大小的指示。请注意,此图通常会高于您的预期,因为.NET还可能在序列化表示中包含元数据。此方法还需要使用[Serializable]
属性标记所有类。
public static long GetSerializedSize(object root)
{
using (var memoryStream = new MemoryStream())
{
var binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(memoryStream, root);
return memoryStream.Length;
}
}