C# 在自定义类型上使用集合初始值设定项语法?

C# 在自定义类型上使用集合初始值设定项语法?,c#,collections,collection-initializer,C#,Collections,Collection Initializer,我有一个很大的静态列表,它基本上是一个查找表,所以我用代码初始化该表 private class MyClass { private class LookupItem { public int Param1 { get; set; } public int Param2 { get; set; } public float Param2 { get; set; } public float Param4

我有一个很大的静态列表,它基本上是一个查找表,所以我用代码初始化该表

private class MyClass
{
    private class LookupItem
    {
        public int Param1    { get; set; }
        public int Param2    { get; set; }
        public float Param2  { get; set; }
        public float Param4  { get; set; }
    }

    private static List<LookupItem> _lookupTable = new List<LookupItem>()
    { 
        new LookupItem() { Param1 = 1, Param2 = 2, Param3 = 3 Param4 = 4 },
        new LookupItem() { Param1 = 5, Param2 = 6, Param3 = 7 Param4 = 8 },
        //etc
    }
}
我真正想做的是对对象本身使用集合初始化器格式,这样我就可以在每一行上去掉
newlookupitem()
。例如:

private static List<LookupItem> _lookupTable = new List<LookupItem>()
{ 
    { 1, 2, 3, 4 },
    { 5, 6, 7, 8 },
    //etc
}
private static List\u lookupTable=new List()
{ 
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
//等
}
这可能吗?我认为这是因为
字典
KeyValuePair
可以用这种方式初始化

国家:

集合初始值设定项允许您指定一个或多个元素 初始化实现的集合类时初始化 IEnumerable。元素初始值设定项可以是一个简单的值 表达式或对象初始值设定项。通过使用集合初始值设定项 您不必指定对的Add方法的多个调用 在源代码中创建类;编译器添加这些调用


这是否意味着我需要在我的
LookupItem
类上实现
IEnumerable
,并返回每个参数?但是我的类不是集合类。

您试图在列表本身上使用集合初始值设定项,而不是在您的类型上使用集合初始值设定项:

// Note the "new List<...>" part - that specifies what type the collection
// initializer looks at...
private static List<LookupItem> _lookupTable = new List<LookupItem>()
{ 
    { 1, 2, 3, 4 },
    { 5, 6, 7, 8 },
}
//请注意“新列表”部分-它指定集合的类型
//初始化器看。。。
私有静态列表_lookupTable=新列表()
{ 
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
}
因此,它正在寻找一个
Add
方法,该方法在
列表中有四个参数,但并不存在


您必须实现自己的集合类才能使用自定义集合初始值设定项。当您使用
List
时,遇到的构造函数调用太多。

我认为您需要创建一个自定义集合,而不是List。例如,将其称为LookupItemTable。给该集合一个Add(int,int,float,float)方法,并让它实现IEnumerable。例如:

class LookupItem
{
    public int a;
    public int b;
    public float c;
    public float d;
}

class LookupItemTable : List<LookupItem>
{
    public void Add(int a, int b, float c, float d)
    {
        LookupItem item = new LookupItem();
        item.a = a;
        item.b = b;
        item.c = c;
        item.d = d;
        Add(item);
    }
}

private static LookupItemTable _lookupTable = new LookupItemTable {
    { 1, 2, 3, 4 },
    { 5, 6, 7, 8 }
};
类查找项
{
公共INTA;
公共int b;
公共浮动c;
公共交通工具d;
}
类LookupItemTable:列表
{
公共无效添加(整数a、整数b、浮点c、浮点d)
{
LookupItem=新的LookupItem();
项目a=a;
项目b=b;
项目c=c;
项目d=d;
增加(项目);
}
}
私有静态LookupItemTable _lookupTable=新的LookupItemTable{
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 }
};
我现在已经尝试了上面的代码,它似乎适合我

这是否意味着我需要在LookupItem类上实现IEnumerable 然后返回每个参数?我的课不是一个收集课

不,这意味着
List
实现了
IEnumerable
,这就是为什么您可以编写

private static List<LookupItem> _lookupTable = new List<LookupItem>()
{ 
    new LookupItem(1, 2, 3, 4),
    new LookupItem(5, 6, 7, 8),
    //etc
}

快速修复:使用带有多个参数的
添加
重载,创建自己的
列表
类型:

class LookupList : List<LookupItem> {
    public void Add(int Param1, int Param2, ... sometype ParamX) {
        this.Add(new LookupItem() { Param1 = Param1, Param2 = Param2, ... ParamX = ParamX });
    }
}
更基本的答案:

你把事情搞混了。简言之:

对象初始值设定项是一种语法技巧,它在后台使用指定的值为每个命名属性调用属性集方法

集合初始值设定项是一种语法技巧,在后台:

  • 对于
    数组
    类型:用项目填充数组
  • 对于必须实现
    IEnumerable
    的任何其他类型:为每个子括号集调用
    Add
    方法
这就是全部。例如,考虑下面的黑客:

public class Hack : IEnumerable {
    public int LuckyNumber { get; set; }
    public double Total { get; private set; }
    public void Add(string message, int operand1, double operand2, double operand3) {
        Console.WriteLine(message);
        this.Total += operand1 * operand2 - operand3;
    }
    public IEnumerator GetEnumerator() { throw new NotImplementedException(); }
}

class Program {
    static void Main(string[] args) {
        Hack h1 = new Hack() {
            { "Hello", 1, 3, 2},
            { "World", 2, 7, 2.9}
        };
        Console.WriteLine(h1.Total);
        Hack h2 = new Hack() { LuckyNumber = 42 };
        Console.WriteLine(h2.LuckyNumber);
    }
}

您永远不应该在实际的程序中这样做,但我希望检查这个示例和结果,特别是在调试一步一步的情况下,将有助于您清楚地理解初始值设定项,并为当前场景选择一个好的解决方案。

而不是使用从List派生的自定义类来模糊List的意图,添加一个调用所需构造函数的简单扩展:

public static class LookupItemListExtensions
{
    public static void Add(this List<LookupItem> lookupItemList, int param1, int param2, float param3, float param4)
    {
        lookupItemList.Add(new LookupItem(param1, param2, param3, param4));
    }
}
公共静态类LookupItemListExtensions
{
公共静态void Add(此列表lookupItemList、int-param1、int-param2、float-param3、float-param4)
{
添加(新的查找项(param1,param2,param3,param4));
}
}

请注意,您是为了简洁而交易清晰性,因此使用时请自行承担风险。使用“new ListItem”可以将F12直接发送给构造函数;这个扩展不会(对其他开发人员来说也不会很明显)。

太棒了。非常感谢。
你不应该在真正的程序中这样做
-好的。在一个真正的程序中你应该做什么?场景:从Java移植,并且有一个类,该类有3个
Add()
重载并实现
IEnumerable
。如果我实现
ICollection
,我将拥有一堆我不想要或不需要的
Remove()
Clear()
方法。是否有其他解决方案可以更清楚地说明如何使用Intellisense使用集合初始值设定项,或者编写文档是我唯一的选择?
    private static LookupList _lookupTable = new LookupList() {                  
        {1,2,3,4},                 
        {2,7,6,3}                
    };
public class Hack : IEnumerable {
    public int LuckyNumber { get; set; }
    public double Total { get; private set; }
    public void Add(string message, int operand1, double operand2, double operand3) {
        Console.WriteLine(message);
        this.Total += operand1 * operand2 - operand3;
    }
    public IEnumerator GetEnumerator() { throw new NotImplementedException(); }
}

class Program {
    static void Main(string[] args) {
        Hack h1 = new Hack() {
            { "Hello", 1, 3, 2},
            { "World", 2, 7, 2.9}
        };
        Console.WriteLine(h1.Total);
        Hack h2 = new Hack() { LuckyNumber = 42 };
        Console.WriteLine(h2.LuckyNumber);
    }
}
public static class LookupItemListExtensions
{
    public static void Add(this List<LookupItem> lookupItemList, int param1, int param2, float param3, float param4)
    {
        lookupItemList.Add(new LookupItem(param1, param2, param3, param4));
    }
}