3

我在 XNA 中遇到了 BoundingSpheres 的问题。我想将 BoundingSphere 添加到 BoundingSpheres 列表中。目前是这样的:

Aircraft(Vector3 pos, float radius, CollisionManager colMan)
{ 
    BoundingSphere sphere = new BoundingSphere(pos, radius);
    colMan.AddSphere(sphere)
}


List<BoundingSphere> spheres = new List<BoundingSphere>();

CollisionManager()
{
    spheres = new List<BoundingSphere>();
}

AddSphere(BoundingSphere boundingSphere)
{
    spheres.Add(boundingSphere);
}

而不是添加一个引用,它似乎是在添加值。我相信这是因为 boundingSpheres 是结构?我怎样才能绕过这个?我尝试了 ref 关键字,但列表中的值仍未更新。

4

3 回答 3

2

直截了当,你不能,至少不能直接。结构是值类型,因此按值传递和存储。即使明智地使用ref关键字也无法绕过它,因为List<T>.Item无法返回对值类型的引用。

解决方法是将你的struct变成 a class,或者嵌入到stuctaclass中,或者,只是处理它是一个值类型的事实并适当地对待它(即,不要尝试修改本地副本,而是替换更改时列出)。最后一个选项是,imo,最好的。

于 2012-12-03T20:03:00.777 回答
0

值类型是按值传递的(这意味着您在方法或容器中获得了新的副本)以避免这种情况,您可以将结构更改为类,向结构声明添加接口并将结构装箱以存储对的引用而是界面。

但是您似乎正在使用可变结构,这是非常危险的,因为您可能会面临非常危险的行为(有关更多详细信息,请参阅被认为有害的可变结构)。

于 2012-12-03T19:57:23.553 回答
0

您必须将定义BoundingSphereclass更改为struct。这是不可能的,因为它是在您无法控制的程序集中定义的。

您不能对结构进行装箱,因为每次拆箱时,您都会得到您所持有的结构的副本。

也就是说,您可以做到这一点的唯一方法(在我看来,这不是一个好主意)是为结构创建一个类包装器,并将所有来自属性的调用委托给内部结构:

public class BoundingSphereWrapper
{
     // Set through constructor.
     private readonly BoundingSphere _boundingSphere = ...;

     // One of the forwarded calls.
     public ContainmentType Contains(BoundingBox box)
     {
         // Forward the call.
         return _boundingSphere.Contains(box);
     }

     // And so on...
}

当然,您不能将这些类实例传递给期望 a 的成员BoundingSphere,并且当您公开底层结构时,您必须尝试检测更改(这几乎是不可能的,除非实例通过引用传递)。

也就是说,虽然,你并不是真的想这样做;该结构的设计者可能出于以下原因选择它作为结构:

  • 虽然是可变的(在处理结构时这是一个禁忌),但它的生命周期是有限的
  • 可能同时实例化了许多这样的实例,并且在堆栈上执行此操作比在堆上执行此操作更有效(这会导致大量第一代垃圾收集,这肯定会对性能产生影响)游戏平台)
于 2012-12-03T20:02:47.257 回答