2012-12-03 44 views
2

我在用XNA BoundingSpheres问题的参考。我想将BoundingSphere添加到BoundingSpheres列表中。目前,它是沿着以下几条线:添加到列表C#结构

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关键字,但值仍然没有在列表中更新。

+0

感谢您的回答。我想我会重新设计一下我的Collision Manager。应该只有数量有限的物体具有移动的碰撞盒,所以我希望能够找到一种不会对性能造成太大影响的方式。 – Bushes

+0

考虑创建一个接口,我们称它为'ICollidable',它表示一个可碰撞的对象并将其边界几何体作为一个属性公开。然后,您可以创建一个可碰撞对象列表,这可能是您想要的,并相应地更新它们。请记住,如果替代方法是堆分配,那么传递大型结构有时可能是有价值的,并且确保在跳到关于其性能的任何结论之前对代码进行概要分析。 –

+0

@ColeCampbell实际上是我最初的想法。尽管我有同样的问题。我在名为CheckCollision(BoundingSphere sphere)的界面中创建了一个检查冲突方法。碰撞管理器然后会调用这个方法并从列表中传递一个球体。通过的球体将是一个副本,但不参考原始的边界球。我无法真正看到解决这个问题的好方法,它不涉及高耦合。 – Bushes

回答

0

值类型是按值传递(这意味着你要在方法或容器中的全新副本),以避免这种情况,你可以你的结构改变类,增加一个接口结构声明和框的结构代替存储对接口的引用。

但似乎你正在使用可变的结构,这是一个非常危险的,因为你可以面对真正的危险行为(见mutable structs considered harmful有详细介绍)。

+0

'可变的结构被认为是有害的,'就像'堆栈是一个实现细节'一样,是当你处理像游戏开发这样的高性能场景时那种窗外事物。避免收集压力可能非常重要,尤其是在移动/控制台平台上,这意味着可变结构可以很好地解决真正的问题。为了这个目的,.NET Framework本身使用可变结构:查看通用List类的枚举器的实现。 –

0

您必须将BoundingSphere的定义从class更改为struct。这是不可能的,因为它在an assembly outside of your control中定义。

你不能框结构,每次拆箱它的时候,你会得到你持有结构的副本。

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

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... 
} 

当然,你不能将这些类的实例传递给期待BoundingSphere成员,你必须尝试和发现变化(这是几乎是不可能的,除非该实例是通过引用传递)当你公开底层结构时。

也就是说,虽然,你真的不希望这样做;该结构的设计人员可能选择它作为一个结构的原因如下:

  • 虽然可变(这是一个没有任何与结构处理时),则寿命旨在限于
  • 有可能是其中很多都是同时实例化的,在堆栈上执行此操作比在堆上执行操作效率更高(这会导致大量第一代垃圾回收,这对于游戏平台的性能肯定会有影响)
2

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

的变通办法是要么把你structclass,或嵌入stuct一个class里面,或者,只是对付它的值类型的事实并进行适当处理(即,不要试图修改本地副本,但在更改时替换列表中的值)。最后一个选项是,imo,最好的。