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

时间:2019-03-19 23:54:08

标签: c# initializer-list

我在玩《太空工程师》,这是一款允许在游戏中编写脚本的游戏。我想编写一个脚本,用某些物品类型重新填充船。

原始代码仅包含项目名称列表:

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

但是我想为不同的物品取回不同的金额。我准备了以下结构式课程:

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 个答案:

答案 0 :(得分:4)

作为迈克尔回答的替代方法,并且为了避免使用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)
};

答案 1 :(得分:4)

集合初始值设定项仅需要具有兼容签名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,并进行了编译。太空工程师需要使用基于Roslyn的C#编译器才能发挥我的答案。

答案 2 :(得分:3)

您不能,对象和集合初始化器没有简化的语法来构造这样的对象列表。您需要指定类型

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

这样的操作荒谬
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#元组是您使用轻量级语法定义的类型。的   优点包括语法更简单,基于以下内容的转换规则   元素的数量(称为基数)和类型,以及   复制,相等性测试和作业的一致规则。作为一个   权衡,元组不支持某些面向对象的习惯用法   与继承相关。

Object and Collection Initializers (C# Programming Guide)

  

C#可让您实例化对象或集合并执行成员   单个语句中分配作业。

相关问题