使用简短的初始化语法来初始化对值列表

Use short initializer syntax to initialize a list of pair values

我在玩 Space 工程师,这是一款允许在游戏中编写脚本的游戏。我想编写一个脚本,用某些类型的物品重新装满一艘船。

原始代码只有项目名称列表:

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

但我想为不同的项目检索不同的金额。我准备了以下结构 class:

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?

你不能,对象和集合初始化程序 没有简写语法来构造这样的对象列表。您需要指定 type.

但是,您可以使用 命名元组

来做一些荒谬的事情
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# tuple types

C# tuples are types that you define using a lightweight syntax. The advantages include a simpler syntax, rules for conversions based on number (referred to as cardinality) and types of elements, and consistent rules for copies, equality tests, and assignments. As a tradeoff, tuples do not support some of the object-oriented idioms associated with inheritance.

Object and Collection Initializers (C# Programming Guide)

C# lets you instantiate an object or collection and perform member assignments in a single statement.

作为 Michael 答案的替代方案,为了避免使用 Builder 方法,您还可以依赖于使用 C# implicit keyword,例如:

public class RequiredItem
{
    //snip

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

现在您可以使用元组创建列表:

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)
};

集合初始值设定项只需要一个具有 兼容签名 Add 方法,并且它不必存在于类型本身上。 (该集合必须实现 IEnumerable 到 "prove" 它是一个集合。)

添加扩展方法...

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 版,并进行了编译。 Space 工程师需要使用基于 Roslyn 的 C# 编译器才能使我的回答生效。