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

发布于 2025-01-03 19:50:50 字数 2017 浏览 2 评论 0原文

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

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

真正的 LookupItem 具有更多属性,因此我添加了一个构造函数以允许更紧凑的初始化格式:

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

        public LookupItem(int param1, int param2, float param3, float param4)
        {
            Param1 = param1;
            Param2 = param2;
            Param3 = param3;
            Param4 = param4;    
        }
    }

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

我真正想做的是对对象本身使用集合初始化程序格式,这样我就可以去掉每一行的new LookupItem()。例如:

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

这可能吗?我喜欢认为这是因为 DictionaryKeyValuePair 可以通过这种方式初始化。

MSDN 指出:

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

这是否意味着我需要在我的 LookupItem 类上实现 IEnumerable 并返回每个参数?不过,我的班级不是收藏班级。

I have a large static list which is basically a lookup table, so I initialise the table in code.

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

The real LookupItem has many more properties, so I added a constructor to allow for a more compact initialisation format:

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

        public LookupItem(int param1, int param2, float param3, float param4)
        {
            Param1 = param1;
            Param2 = param2;
            Param3 = param3;
            Param4 = param4;    
        }
    }

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

What I'd really like to do is use the collection initialiser format for the object itself so I can get rid of the new LookupItem() on every line. eg:

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

Is this possible? I like to think it is because the KeyValuePair's of a Dictionary<> can be initialised in this way.

MSDN States:

Collection initializers let you specify one or more element
intializers when you initialize a collection class that implements
IEnumerable
. The element initializers can be a simple value, an
expression or an object initializer. By using a collection initializer
you do not have to specify multiple calls to the Add method of the
class in your source code; the compiler adds the calls.

Does this mean I need to implement IEnumerable on my LookupItem class and return each parameter? My class isn't a collection class though.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

属性 2025-01-10 19:50:50

我认为你需要创建一个自定义集合而不是列表。例如,将其称为 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 }
};

我现在已经尝试了上面的代码,它似乎对我有用。

I think you need to make a custom collection instead of List. Call it LookupItemTable, for example. Give that collection an Add(int, int, float, float) method and have it implement IEnumerable. For example:

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

I've now tried the above code and it seems to work for me.

忆梦 2025-01-10 19:50:50

快速修复:使用带有多个参数的 Add 重载创建您自己的 List 类型:

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

现在完全按照您想要的方式工作:

    private static LookupList _lookupTable = new LookupList() {                  
        {1,2,3,4},                 
        {2,7,6,3}                
    };

更基本答案:

您混淆了对象初始值设定项集合初始值设定项。简而言之:

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

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

  • 对于 Array 类型:用项目填充数组
  • 对于任何其他类型,必须实现 IEnumerable< /code>:为每个子括号集调用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);
    }
}

您永远不应该在真实的程序中执行此操作,但我希望检查此示例和结果,特别是如果您调试单步调试它,将帮助您清楚地理解初始化程序并为您当前的选择一个好的解决方案设想。

Quick fix : Make your own List type with an Add overload that takes multiple arguments:

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

Now works exactly as you want:

    private static LookupList _lookupTable = new LookupList() {                  
        {1,2,3,4},                 
        {2,7,6,3}                
    };

More fundamental answer:

You're mixing up object initializers and collection initializers. Put simply:

Object initializers are a syntactic trick that, in the background call the property set methods for each named property with the value specified.

Collection initializers are a syntactic trick that, in the background:

  • For an Array type: Fill the array with the items
  • For any other type, which must implement IEnumerable: Call the Add method for each sub-bracketed set.

That is all there is to it. Consider for example the following hack:

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

You should never do this in a real program, but I hope examining this example and the results, especially if you debug step through it, will help you understand the initializers clearly and choose a good solution for your current scenario.

时光匆匆的小流年 2025-01-10 19:50:50

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

// 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 },
}

因此它在 List 上寻找带有四个参数的 Add 方法,并且那不存在。

您必须实现自己的集合类才能使用自定义集合初始值设定项。当您使用 List 时,您会陷入构造函数调用的困境。

You're trying to use a collection initializer on the list itself, not on your type:

// 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 },
}

So it's looking for an Add method with four parameters on List<T>, and that doesn't exist.

You would have to implement your own collection class to use a custom collection initializer. While you're using List<T>, you're stuck with the constructor calls you've got.

楠木可依 2025-01-10 19:50:50

不要使用从 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));
    }
}

请注意,您是为了简洁而牺牲清晰度,因此使用风险自负。使用“new ListItem”可以让您直接按 F12 进入构造函数;这个扩展不会(对于其他开发人员来说也不会是显而易见的)。

Rather than obscure the intent of List with a custom class deriving from List<LookupItem>, add a simple extension that calls the required constructor:

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

Note that you're trading clarity for brevity, so use at your own risk. Using "new ListItem" lets you F12 directly to the constructor; this extension does not (nor will it ever likely be obvious to other developers).

猥琐帝 2025-01-10 19:50:50

这是否意味着我需要在 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
}

它也意味着如果你的 LookupItem 是一个集合,实现了 IEnumerable,你可以这样写:

private static List<LookupItem> _lookupTable = new List<LookupItem>()
{ 
    new LookupItem { new Item(), new Item() },
    new LookupItem { new Item(), new Item() }
}

Does this mean I need to implement IEnumerable on my LookupItem class
and return each parameter? My class isn't a collection class though.

No, it means that List<LookupItem> implements IEnumerable, which is why you can write

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

It also means that if your LookupItem was a collection that implemented IEnumerable, you could have written:

private static List<LookupItem> _lookupTable = new List<LookupItem>()
{ 
    new LookupItem { new Item(), new Item() },
    new LookupItem { new Item(), new Item() }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文