无法在迭代期间获得单独的引用

Unable to get separate references during iteration

我正在尝试遍历实现特定接口的列表成员,称为 ImplementsGraphics,然后调用方法 GetModels 并将 return 结果添加到列表.

但是,每当我尝试遍历我的对象并执行强制转换操作时,我似乎在我的迭代过程中覆盖了相同的引用。我推断我的问题与我在哪里、何时以及如何实例化我的变量有关,但我无法准确解读预期的行为是什么。

我尝试了以下代码的多种排列:

public List<Model> GetModels()
        {
            var models = new List<Model>();

            foreach (Actor actor in registeredActors.Where(n=>n is ImplementsGraphics))
            {
                var graphicActor = (ImplementsGraphics)actor;
                models.AddRange(graphicActor.GetModels());
            }
            return models;
        }

问题行是 var graphicActor = (ImplementsGraphics)actor;,但我不知道如何编写它以声明 graphicsActor 不会覆盖存储在模型中的现有实例。

在我的前几轮故障排除之前,我有

public List<Model> GetModels()
        {
            var models = new List<Model>();

            foreach (Actor actor in registeredActors)
            {
                if((ImplementsGraphics)actor != null)
                    models.AddRange(((ImplementsGraphics)actor).GetModels());
            }
            return models;
        }

我原以为 actor 在迭代中是安全的,但显然不是。

期望的行为: Return 一个列表,它是实现 ImplementsGraphics

的 RegisteredActors 中永远的 Actor GetModels() 的所有 return 结果

实际行为: Return 是一个列表,与实现 ImplementsGraphics 的已注册 Actor 中的每个 Actor 重复相同的 return 值。

编辑:

在 class StaticActor 中,它是 Actor 的子项并实现 ImplementsGraphics 其定义如下:

public List<Model> GetModels()
    {
        foreach (ModelMesh mesh in model.Meshes)
        {
            foreach (BasicEffect effect in mesh.Effects)
            {
                effect.World = this.Transform.WorldMatrix;
            }
        }
        return new List<Model> { Model };
    }

此外,我还尝试了另外两种同样失败的方法。一个 for 循环,遍历所有 RegisteredActors,并检查它们是否实现了 ImplementsGraphics,通过它们在 RegisteredActors

中的索引显式调用它们

还有一个 LINQ 查询 var models = RegisteredActors.Where(n=>n is ImplementsGraphics).SelectMany(n=>((ImplementsGraphics)n).GetModels())

编辑 2:

我的 classes 的定义在很大程度上是无关紧要的,如果你想要一个我遇到问题的行为的可重现示例,这里有一个简单得多的示例。

class MyClass
{
    MyOtherClass foo = new MyOtherClass();
    int bar = 0;

    MyOtherClass GetOtherClass()
    {
        foo.bar = bar;
        return foo;
    }
}

class MyOtherClass
{
    int bar = 0;
}

List<MyClass> MyCollection = new List<MyClass> {new MyClass(bar = 1), new MyClass(bar = 2), new Myclass(bar = 3)};
List<MyOtherClass> MyOtherCollection = new List<MyOtherClass>();
foreach(MyClass member in MyCollection)
{
    MyOtherCollection.Add(member.GetOtherClass());
}

如果您执行上述代码,我预计 MyOtherCollection 的条形属性的值将是:1、2、3

然而,实际的结果是: 在第一次迭代期间,值为 1 在第二次迭代期间,值为 2、2 在第三次迭代期间,值为 3, 3, 3

我会出现,因为 none 所提供的代码状态仅暗示您正在尝试重用对单个 Model 实例的引用来绘制多个对象。然后您将同一实例的多个引用添加到 List.

解决方案可能就像从所有 Model 变量 and/or 容器对象中删除 static 修饰符一样简单。

通常,解决方案是在将对象添加到 List 时创建对象的 Deep Copy,但是,在 XNA 中无法直接执行此操作*1. (不是你想要的)

最好让每个Actor,或StaticActor对象直接通过接口中的GetModels()方法传递自己的Model(s)实施,而不是使用额外的 class MyOtherClass.

*1。 XNA 不会为可用的 Model class. It is possible to do this using reflection. In MonoGame, there is a public Constructor 公开 public 构造函数。


我倾向于根据 "StaticCollidables"、"DrawableStaticCollidables" 和 "DrawableMovingCollidables"...

此技术可能需要更多的前期编码(因此不像 "elegant"),但是,它在内存开销(8 字节 + (4(32 位)或 8(64 bit) 字节取决于 sizeof(Object)) 每 List) 和 CPU 开销(无转换或 is)。


如果您试图重复使用同一个模型,但将其放置在不同的位置,请使用 DrawInstancedPrimitives 方法,使用模型的每个 Mesh 中包含的 VertexBuffer


请评论以上哪些解决方案适合您(如果有)。如果我遗漏了什么,请告诉我,以便我可以更正答案。