Возвращаемый список объектов определенного производного типа - PullRequest
0 голосов
/ 08 мая 2018

Я должен предварять это, говоря, что это будет реализовано в Unity, поэтому я могу использовать некоторые функции и имена классов оттуда, но здесь идет:

У меня есть класс для возможных типов элементов в моей игре, который будет сохранен в файле JSON:

public class Item
{
    //Properties galore
}

public class Weapon : Item
{
    //All my weapon stats
}

public class Projectile : Weapon
{
    //All my projectile weapon stats
}

Так что теперь я могу взять кучу статистики и оружия. Например, текущий инвентарь моего игрока хранится в списке:

List<Item> playerInventory = new List<Item>();

//And then I go on and add my inventory items from a stored file, etc.

Итак, пуф, теперь у моего игрока есть инвентарь. Ура. К сожалению, я изо всех сил пытаюсь найти способ получить список ПРОСТОГО Оружия или ПРОСТОГО Оружия Снаряда. Я мог бы добавить параметр «тип» в мой файл JSON, который содержит значения по умолчанию для каждого оружия и т. Д., Но кажется, что в C # есть способ сделать что-то умное, например

List<Weapon> weaponList = new List<Weapon>();

foreach(Item<Weapon> i in playerInventory)
{
   weaponList.Add(i);
}

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

Спасибо за любую помощь, вы можете предоставить!

Ответы [ 3 ]

0 голосов
/ 08 мая 2018

Вы можете использовать метод LINQ OfType для фильтрации списка. Это также автоматически приводит к правильному типу результатов.

var weapons = inventory.OfType<Weapon>();
var projectiles = inventory.OfType<Projectile>();

Обратите внимание, что ваша объектная модель указывает, что Снаряд является типом Оружия (это то, что означает отношение наследования), поэтому в моем примере weapons также будет содержать снаряды.

Если вы хотите исключить определенные вещи (например, получить список всех видов оружия, которые не являются снарядами), вы можете использовать дополнительное условие Where для специальной фильтрации.

var nonProjectileWeapons = inventory
    .OfType<Weapon>()
    .Where
    (
        weapon => !(weapon is Projectile) 
    );

Во всех случаях вышеприведенное вернет IEnumerable<Weapon>, и это все, что вам обычно нужно. Если вам нужен конкретный бетон List, просто добавьте ToList() в конец.

List<Weapon> nonProjectileWeapons = inventory
    .OfType<Weapon>()
    .Where
    (
        weapon => !(weapon is Projectile) 
    )
    .ToList();

Конечно, если вам нужны только экземпляры конкретного конкретного класса Weapon (при условии, что он конкретен - вероятно, он должен быть абстрактным), вы можете выполнить прямое сравнение типа в предложении where. Для полноты приведу пример, но я настоятельно рекомендую вам вернуться к своей объектной модели, если вы обнаружите, что делаете такие вещи. Если метательное оружие не входит в список оружия, оно не должно иметь наследственных отношений; возможно, вам нужна другая концепция в вашей модели - например, возможно, Weapon и ProjectileWeapon должны наследоваться от BaseWeapon, но не иметь отношений наследования между собой.

В любом случае, вот оно.

List<Weapon> unspecializedWeapons = inventory
    .OfType<Weapon>()
    .Where
    (
        weapon => weapon.GetType() == typeof(Weapon) 
    )
    .ToList();
0 голосов
/ 08 мая 2018

для вашего случая использования вы не можете использовать OfType, потому что он проверяет тип объекта с помощью оператора is (возвращает все объекты в дереве наследования )

Я предлагаю вам написать метод расширения

public static class ListExtensions
{
    public static IEnumerable<TType> IsTypeOf<TType>(this IEnumerable input)
        where TType : class
    {
        foreach (object o in input)
        {
            if (o.GetType() == typeof(TType)) // take note of this, don't use is
            {
                yield return (TType)o;
            }
        }
    }
}

Как пользоваться

var playerInventory = new List<Item>();

playerInventory.Add(new Weapon());
playerInventory.Add(new Weapon());
playerInventory.Add(new Weapon());
playerInventory.Add(new Weapon());
playerInventory.Add(new Projectile());
playerInventory.Add(new Projectile());

// player inventory should have 4 weapons
playerInventory.IsTypeOf<Weapon>().Should().HaveCount(4);
// player inventory should have 2 projectiles
playerInventory.IsTypeOf<Projectile>().Should().HaveCount(2);

Надеюсь, это поможет.

0 голосов
/ 08 мая 2018

Вы можете сделать это, используя linq:

List<Item> inventory = new List<Item>();
// Fill inventory with items of different type.

List<Weapon> weapons = inventory.Where(item => item.GetType() == typeof(Weapon)).Cast<Weapon>().ToList();
List<Projectile> weapons = inventory.Where(item => item.GetType() == typeof(Projectile)).Cast<Projectile>().ToList();

Убедитесь, что вы добавили using System.Linq; для его работы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...