Невозможно получить отдельные ссылки во время итерации - PullRequest
0 голосов
/ 17 февраля 2019

Я пытаюсь перебрать членов списка, которые реализуют определенный интерфейс, называемый ImplementsGraphics, а затем вызвать метод GetModels и добавить возвращаемый результат в список.

Однако всякий раз, когда бы ниЯ пытаюсь перебрать свои объекты и выполнить операцию приведения. Кажется, я перезаписываю ту же ссылку во время итерации.Я пришел к выводу, что моя проблема связана с тем, где, когда и как я создаю экземпляры своих переменных, но я не могу точно определить, каково предполагаемое поведение.

Я пробовал многочисленные перестановки следующего кода:

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 безопасен на протяжении итерации, но, видимо, нет.

Желаемое поведение: возвращает список, который представляет собой все возвращаемые результаты GetModels() для любого Актора в RegisteredActors, который реализует ImplementsGraphics

Фактическое поведение: Возвращает список, который является тем жевозвращаемое значение повторяется для каждого актера в зарегистрированном акторе, который реализует ImplementsGraphics.

РЕДАКТИРОВАТЬ:

в классе 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:

Определения моих классов в значительной степени не имеют значения, если вы хотите воспроизводимый пример поведения, с которым у меня проблемы, вот гораздо более простой пример.

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

1 Ответ

0 голосов
/ 24 февраля 2019

Я бы появился, поскольку ни одно из предоставленных состояний кода не подразумевает, что вы пытаетесь повторно использовать ссылку на один экземпляр Model для рисования нескольких объектов.Затем вы добавляете несколько ссылок одного и того же экземпляра в List.

. Решение может быть таким же простым, как удаление модификатора static из всех Model переменных и / или контейнерных объектов.

Как правило, решением будет создание Deep Copy объекта при его добавлении в List, однако в XNA * 1 сделать это напрямую невозможно.(не то, что вы хотели бы)

Было бы лучше разрешить каждому Actor или StaticActor объекту напрямую передавать свои собственные Model (s) через метод GetModels() вреализация интерфейса, вместо использования дополнительного класса MyOtherClass.

* 1.XNA не предоставляет открытый конструктор для класса Model . возможно сделать это с помощью отражения.В MonoGame доступен общедоступный конструктор .


Я склонен разбивать мои производные классы и последующие List s на основе таких свойств, как "StaticCollidables", "DrawableStaticCollidables" и "DrawableMovingCollidables" ...

Для этого метода может потребоватьсяболее предварительное кодирование (и, следовательно, не такое «элегантное»), но оно более эффективно с точки зрения затрат памяти (8 байтов + (4 (32-битных) или 8 (64-битных) байтов в зависимости от sizeof(Object)) на Список ) и загрузка ЦП (без приведения или is).


Если вы пытаетесь повторно использовать одну и ту же модель, но размещаете ее в разных местах, используйте метод DrawInstancedPrimitives , используя VertexBuffer s, содержащиеся в каждом Mesh элементамодель.


Пожалуйста, прокомментируйте, какое из вышеуказанных решений сработало для вас (если есть).Если я что-то пропустил, пожалуйста, дайте мне знать, чтобы я мог исправить ответ.

...