Bow*_*opa 9 c# generics xna struct boxing
我正在创建一个用于XNA游戏的消息传递系统.我的消息类型是结构,因为我希望它们以值类型的方式运行.
struct MyMessageType1 : IMessage {}
struct MyMessageType2 : IMessage {}
List<IMessage> messageQueue = new List<IMessage>();
Run Code Online (Sandbox Code Playgroud)
我希望能够在我的消息队列中存储不同类型的消息,但我想这样做而不会将它们中的任何一个装箱.
如果我有结构实现了一个接口,如IMessage,我尝试将它们存储在List中,它们就会被装箱.
我不知道所有可能的消息类型,所以我不能只为每种类型硬编码一个列表.
所以问题是如何在不加框的情况下存储不同类型的结构列表?
这是不可能做到的.
但是,您可以使用两个列表(List<MyMessageType1>和List<MyMessageType2>)来模拟事物.
然后你编写一个超级索引(可能只是另一个整数数组(long?)),以便(可以)间接地对一个项目进行寻址,就像它是一个列表一样.
您可能希望优化索引(runlength编码:仅存储后备阵列切换的索引:当迭代已知在其中一个后备阵列中连续的子范围时,这也将非常有用)
列表在内部使用数组存储,所以 - 你没有拳击 - 快速随机访问 - 与list.ForEach的炽热迭代
查看StructLayout属性,并以某种方式通过执行所有操作来模拟Union.如果你真的准备好弄脏你的东西,抛出unsafe {}块(并使用/ unsafe编译)......但是,认真考虑P/Invoke C DLL或使用C++/CLI如果它很重要那么多
因为我真的很喜欢Marc Gravell指出你可以使用我提到的StructLayout这一事实,以相同的偏移量确定联合 .NET结构的所有三个成员; 我想我会去额外的步骤,看看我是否能做出很多的地狱更漏 tranparent依然.这非常接近透明:
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace LeakyAbstractions
{
struct TypeA {}
struct TypeB {}
struct TypeC {}
[StructLayout(LayoutKind.Explicit)] internal struct AnyMessage {
[FieldOffset(0)] public TypeA A;
[FieldOffset(0)] public TypeB B;
[FieldOffset(0)] public TypeC C;
AnyMessage(TypeA a) { A = a; }
AnyMessage(TypeB b) { B = b; }
AnyMessage(TypeC c) { C = c; }
public static implicit operator TypeA(AnyMessage msg) { return msg.A; }
public static implicit operator TypeB(AnyMessage msg) { return msg.B; }
public static implicit operator TypeC(AnyMessage msg) { return msg.C; }
public static implicit operator AnyMessage(TypeA a) { return a; }
public static implicit operator AnyMessage(TypeB b) { return b; }
public static implicit operator AnyMessage(TypeC c) { return c; }
}
public class X
{
public static void Main(string[] s)
{
var anyMessages = new List<AnyMessage> {
new TypeA(),
new TypeB(),
new TypeC(),
};
TypeA a = anyMessages[0];
TypeB b = anyMessages[1];
TypeC c = anyMessages[2];
anyMessages.Add(a);
anyMessages.Add(b);
anyMessages.Add(c);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我将把这个可怜男人的变种作为锻炼的问题留给你.简单的方法是向结构添加一个字段AnyMessage,但根据有效负载,其他策略可能更多(空间/时间)有效.
我的0.02美元
哦,我从来没有真正这样做过,因为它似乎过于复杂.我假设你有正当理由来优化它
PS.如果你在这里阅读我的答案之后问这个问题(昨天:我应该使用结构或类来表示一个Lat/Lng坐标吗?),我将快速判断这个过早的优化
基本上,你不能很好 ;
object或接口处理:盒装object,盒装dynamic:基本上object,盒装存在是该选项,然而,封装在一个更大的结构中的对象,即
struct AnyMessage {
public TypeA A;
public TypeB B;
public TypeC C;
}
struct TypeA {...}
struct TypeB {...}
struct TypeC {...}
Run Code Online (Sandbox Code Playgroud)
现在,这应该有效,但显然是更大的缺点.您可以使用显式布局来解决这个问题,将它们全部放在字节0(建立联合),但我怀疑这在xbox上是不允许的.但在常规.NET上:
[StructLayout(LayoutKind.Explicit)] struct AnyMessage {
[FieldOffset(0)] public TypeA A;
[FieldOffset(0)] public TypeB B;
[FieldOffset(0)] public TypeC C;
}
Run Code Online (Sandbox Code Playgroud)
您可以创建一个无需装箱即可存储结构的队列,然后使用具有通用方法的接口处理它,如下所示:
interface IMessageProcessor
{
void Process<T>(T message) where T : struct, IMessage;
}
class MessageQueue
{
abstract class TypedMessageQueue
{
public abstract void ProcessNext(IMessageProcessor messageProcessor);
}
class TypedMessageQueue<T> : TypedMessageQueue where T : struct, IMessage
{
Queue<T> m_queue = new Queue<T>();
public void Enqueue(T message)
{
m_queue.Enqueue(message);
}
public override void ProcessNext(IMessageProcessor messageProcessor)
{
messageProcessor.Process(m_queue.Dequeue());
}
}
Queue<Type> m_queueSelectorQueue = new Queue<Type>();
Dictionary<Type, TypedMessageQueue> m_queues =
new Dictionary<Type, TypedMessageQueue>();
public void Enqueue<T>(T message) where T : struct, IMessage
{
TypedMessageQueue<T> queue;
if (!m_queues.ContainsKey(typeof(T)))
{
queue = new TypedMessageQueue<T>();
m_queues[typeof(T)] = queue;
}
else
queue = (TypedMessageQueue<T>)m_queues[typeof(T)];
queue.Enqueue(message);
m_queueSelectorQueue.Enqueue(typeof(T));
}
public void ProcessNext(IMessageProcessor messageProcessor)
{
var type = m_queueSelectorQueue.Dequeue();
m_queues[type].ProcessNext(messageProcessor);
}
}
Run Code Online (Sandbox Code Playgroud)
您为每种类型的消息保留一个单独的队列,使用它可以完全避免消息装箱,无需任何StructLayout技巧,也无需事先了解所有可能的消息类型。
| 归档时间: |
|
| 查看次数: |
2903 次 |
| 最近记录: |