添加对列表c#struct的引用

时间:2012-12-03 19:45:47

标签: c# list xna

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

3 个答案:

答案 0 :(得分:2)

直言不讳,你不能,至少不能直接。结构是value types,因此按值传递和存储。即使明智地使用ref关键字也无法解决问题,因为List<T>.Item无法返回对值类型的引用。

解决方法是将struct转换为class,或将stuct嵌入class,或者只处理它是一个事实值类型并对其进行适当处理(即,不要尝试修改本地副本,但在更改时替换列表中的值)。最后一个选项是,imo,最好的。

答案 1 :(得分:0)

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

但似乎你正在使用可变结构,这是非常危险的,因为你可能面临非常危险的行为(更多细节见mutable structs considered harmful)。

答案 2 :(得分: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的成员,并且您必须尝试检测更改(这几乎不可能,除非实例通过引用传递)你暴露了底层结构。

但是,你真的不想这样做;结构的设计者可能选择它作为结构,原因如下:

  • 虽然可变(在处理结构时是禁忌),但生命周期有限
  • 可能有很多这些同时被实例化,并且在堆栈上执行此操作比在堆上执行此操作更有效(这将导致许多第一代垃圾收集,这肯定会对在游戏平台上的表现)