Используйте короткий синтаксис инициализатора для инициализации списка значений пары - PullRequest
1 голос
/ 20 марта 2019

Я играю в Space Engineers, это игра, которая позволяет создавать скрипты в игре.Я хотел бы написать скрипт, который заправляет корабль определенными типами предметов.

В исходном коде просто есть список названий предметов:

public readonly List<RequiredItem> requiredItemNames = new List<String>{
    "ilder_Component/Construction", 
    "nt/Computer",
    "_Component/Girder",
    "ponent/MetalGrid",
    "Motor",
    "MyObjectBuilder_Component/SteelPlate",
};

Но я бы хотел получить разныесуммы для разных предметов.Я подготовил следующий класс struct-ish:

public class RequiredItem {
     public RequiredItem(string pattern, double req) {
         this.pattern = pattern;
         this.amountRequired = req;
     }
     string pattern;
     double amountRequired = 0;
}

Я хотел бы инициализировать список без повторяющихся new RequiredItem("name", 12345).Я немного знаю этот синтаксис из C ++, но не из C #.Я попробовал следующее:

public readonly List<RequiredItem> requiredItemNames = new List<String>{
    {"ilder_Component/Construction", 300},  // construction comp
    {"nt/Computer",150},
    {"_Component/Girder",100},
    {"ponent/MetalGrid",70},
    {"Motor",150},
    {"MyObjectBuilder_Component/SteelPlate",333}
};

Это дает мне ошибку:

Error: No oveload for method 'Add' takes 2 arguments

Так что я полагаю, что он пытается поместить пары в List.Add вместо моего конструктора.Как мне установить, что я хочу, чтобы предметы были сконструированы и затем помещены в Add?

Ответы [ 3 ]

4 голосов
/ 20 марта 2019

В качестве альтернативы ответу Майкла и во избежание использования метода Builder вы также можете использовать неявное ключевое слово C # , например:

public class RequiredItem
{
    //snip

    public static implicit operator RequiredItem((string pattern, double req) ri)
    {
        return new RequiredItem(ri.pattern, ri.req);
    }
}

ИТеперь вы можете создать свой список, используя Tuples:

public readonly List<RequiredItem> requiredItemNames = new List<RequiredItem>
{
    ("ilder_Component/Construction", 300),  // construction comp
    ("nt/Computer",150),
    ("_Component/Girder",100),
    ("ponent/MetalGrid",70),
    ("Motor",150),
    ("MyObjectBuilder_Component/SteelPlate",333)
};
4 голосов
/ 20 марта 2019

Инициализаторам коллекции просто требуется метод Add с совместимой подписью , и он не должен существовать в самом типе. (Однако коллекция должна реализовывать IEnumerable, чтобы "доказать", что это коллекция.)

Добавить метод расширения ...

public static class RequiredItemListExtensions
{
    public static void Add(this List<RequiredItem> list, string pattern, double req)
    {
        list.Add(new RequiredItem(pattern, req));
    }
}

Тогда вы можете инициализировать его так, как хотите.

public readonly List<RequiredItem> requiredItemNames = new List<RequiredItem>
{
    {"ilder_Component/Construction", 300},
    {"nt/Computer",150},
    {"_Component/Girder",100},
    {"ponent/MetalGrid",70},
    {"Motor",150},
    {"MyObjectBuilder_Component/SteelPlate",333}
};

Насколько я помню, при реализации Roslyn Microsoft удалось убрать проверку, которая помешала разрешению метода выбрать метод расширения. Это изменение, специфичное для Roslyn, а не для версии. В моем тесте, даже когда я опускаю свойство LangVersion до 3,0 (где инициализаторы коллекции были впервые введены, но методы расширения еще не выбраны), он все равно работает, тогда как компилятор, предшествующий Roslyn, все равно будет выдавать ошибку в вопрос.

Обновление: Подтверждено. Я нашел установку VS 2013, попробовал тот же код с явно выбранной версией 5.0, и он выдал ту же ошибку. Я загрузил тот же проект в VS 2015, версия 5.0 все еще выбрана, и он скомпилирован. Для моего ответа на работу космическим инженерам потребуется использовать компилятор C # на основе Roslyn.

3 голосов
/ 20 марта 2019

Вы не можете Инициализаторы объектов и коллекций не имеют сокращенного синтаксиса для составления списка объектов, подобного этому. Вам нужно будет указать тип .

Однако вы можете сделать что-то бессмысленное , например, используя Именованные кортежи

public static List<RequiredItem> Builder(params (string pattern, double req)[] array)
   => array.Select(x => new RequiredItem(x.pattern, x.req)).ToList();


public readonly List<RequiredItem> requiredItemNames = Builder(
   ("ilder_Component/Construction", 300), // construction comp
   ("nt/Computer", 150),
   ("_Component/Girder", 100),
   ("ponent/MetalGrid", 70),
   ("Motor", 150),
   ("MyObjectBuilder_Component/SteelPlate", 333));

Дополнительные ресурсы

Типы кортежей C #

Кортежи C # - это типы, которые вы определяете с использованием упрощенного синтаксиса. Преимущества включают в себя более простой синтаксис, правила для преобразования на основе количество (называемое количеством элементов) и типы элементов, а также согласованные правила для копий, тесты на равенство и задания. Как компромисс, кортежи не поддерживают некоторые объектно-ориентированные идиомы связанные с наследованием.

Инициализаторы объектов и коллекций (Руководство по программированию в C #)

C # позволяет создать экземпляр объекта или коллекции и выполнить член присваивания в одном выражении.

...