【问题标题】:Supporting collection initialization syntax for immutable collections - init modifiers for methods?支持不可变集合的集合初始化语法 - 方法的初始化修饰符?
【发布时间】:2021-11-17 02:35:04
【问题描述】:

我需要实现一个支持集合初始化语法的不可变集合。问题是为了支持集合初始化语法,集合必须提供适当的公共 Add() 方法。但是,如果集合提供公共 Add() 方法,则它不再是不可变的。

我想要实现的示例:

    var element = new MyElement();
    var collection1 = new MyImmutableCollection { element };
    var collection2 = new MyImmutableCollection { "ABC" };

为了使其工作,我需要 MyImmutableCollection 来实现 IEnumerable 并为 Add() 方法提供适当的签名(有关集合初始化的更多信息是 here):

class MyElement
{
    public MyElement()
    {
    }

    public MyElement(string label)
    {
        Label = label;
    }

    public string Label { get; set; }
}

class MyImmutableCollection : IEnumerable<MyElement>
{
    readonly List<MyElement> list = new List<MyElement>();

    #region Collection initialization support which breaks immutability

    public void Add(MyElement element)
    {
        list.Add(element);
    }

    public void Add(string label)
    {
        Add(new MyElement(label));
    }

    #endregion

    public MyElement this[int index]
    {
        get { return list[index]; }
        set { list.Insert(index, value); }
    }

    #region IEnumerable support

    public IEnumerator<MyElement> GetEnumerator()
    {
        return list.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    #endregion
}

但是,Add() 方法的存在打破了不变性。我想知道,是否有任何新的方法来实现这个目标?我在 StackOverflow 上看到了这个问题 - Can I initialize a BCL immutable collection using braces? - 当时似乎没有合适的解决方案,但这个问题已经很老了,希望 C# 中有一些新功能可用?我已经阅读了有关为不可变对象提供对象初始化的方法的 init 修饰符的介绍 (here),但似乎是 was reverted 的功能。我想也许有一些功能可以使 Add() 方法仅可用于初始化?

更新。我可能只是将构造函数添加到不可变集合中,例如 new MyImmutableCollection( /* items */ )。但是,使用构造函数可能涉及冗长的语法,尤其是当您需要为每个元素传递多个参数时。使用构造函数的示例:

var collectionA = new MyImmutableCollection(new (int code, string description)[] {
    ( 1, "One" ),
    ( 2, "Two" ),
});

集合初始化语法示例:

var collectionB = new MyImmutableCollection
{
    { 1, "One" },
    { 2, "Two" },
};

集合初始化语法更简洁,因此更可取。

这就是我们需要添加到类中以支持上面的构造和集合初始化语法:

public MyImmutableCollection(IEnumerable<(int code, string description)> collection)
{
    // omitted for brevity
}

public void Add(int code, string description)
{
    // omitted for brevity
}

【问题讨论】:

  • “我需要实现一个支持集合初始化语法的不可变集合。” 出于好奇,您能解释一下为什么需要这个吗?
  • 使用生成器。 new ImmutableCollectionBuilder { /*items*/ }.Build(); Build 方法使用内部构造函数为不可变集合提供其项。
  • "但是,如果集合提供公共的 Add() 方法,它就不再是不可变的。" - 这并不完全正确 - 因为你可以有任意的 Add() 参数,所以你可以通过使用一个虚拟集合来invert 接收Add 扩展调用,同时在额外的情况下构建不可变的集合状态范围。我想知道ref 参数是否也有效......
  • @Dai 你能发布这个想法(包括实际代码)作为答案吗?
  • @madreflection,谈到构造函数,我可能只是将构造函数添加到不可变集合中,例如 new MyImmutableCollection( /* items */ )。无需为此使用特殊的构建器。但是,使用构造函数可能涉及冗长的语法,尤其是当您需要为每个元素传递多个参数时。集合初始化语法更简洁,因此更可取。

标签: c# immutability immutable-collections collection-initializer


【解决方案1】:

你做不到。您可以通过如下简单的方式实现它:

class MyImmutableCollection : IEnumerable<MyElement>
    {
        readonly List<MyElement> list = new List<MyElement>();

        public MyImmutableCollection(IEnumerable<MyElement> list)
        {
            this.list.AddRange(list);
        }

        private MyImmutableCollection()
        {
        }

        public MyElement this[int index]
        {
            get { return list[index]; }
        }

        public IEnumerator<MyElement> GetEnumerator()
        {
            return list.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

以下是使用方法:

var list = new List<MyElement> { new MyElement() };
MyImmutableCollection immutableList = new MyImmutableCollection(list);

另外,你可以添加一个扩展方法:

public static MyImmutableCollection ToImmutableCollection(this IEnumerable<MyElement> elements)
{
     MyImmutableCollection list = new MyImmutableCollection(elements);
     return list;
}

使用它更简单:

 var list = new List<MyElement> { new MyElement() };
 list.ToImmutableCollection();

任何方式,您都可以使用库 System.Collections.Immutable 无需实现,以下是如何使用它:

ImmutableList.Create(new MyElement());

注意:可以通过Nuget链接https://www.nuget.org/packages/System.Collections.Immutable添加

【讨论】:

  • “你做不到。”
猜你喜欢
  • 1970-01-01
  • 2017-08-30
  • 2011-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-04
相关资源
最近更新 更多