【问题标题】:Initialize get-only collection in object initializer from existing collection从现有集合初始化对象初始化器中的 get-only 集合
【发布时间】:2018-10-05 15:02:51
【问题描述】:

我有一个具有仅获取集合属性的类。我想用现有集合中的值初始化集合。

我知道可以初始化集合using a collection initializer。我还可以创建对象,然后在集合上使用AddRange 来添加现有集合的项目。但是,这将创建具有空列表的对象,然后添加现有项目。

有没有一种方法可以首先正确初始化 List 来创建对象(当然不添加构造函数)?

using System.Collections.Generic;

namespace EmptyConsoleApp
{
    internal class Program
    {
        public static void Main(string[] args)
        {
            // Compiles, but is not what I need
            var firstHolder = new Holder()
            {
                TheList = {"A", "B"}
            };

            // Compiles, but initializes the list after object creation
            var existingList = new List<string>() {"Foo", "Bar"};
            var secondHolder = new Holder();
            secondHolder.TheList.AddRange(existingList);

            // Does not compile
            var thirdHolder = new Holder()
            {
                TheList = {existingList}
            };
        }
    }

    internal class Holder
    {
        public Holder()
        {
            TheList = new List<string>();
        }

        public List<string> TheList { get; }
    }
}

【问题讨论】:

  • 嗯,它是一个只读属性。为什么你期望你可以在不使用构造函数的情况下从外部初始化它?这正是构造函数存在的原因

标签: c#


【解决方案1】:

没有。您不能从集合初始值设定项中分配此只读属性。毕竟是只读的。

TheList = { "A", "B" } 有效,因为它在 TheList 上调用 Add(每添加一个项目一次),它不会创建和分配新实例,这是不允许的。

TheList = { existingList } 不起作用,因为存在打字问题(TheList = { existingList[0] } 起作用)。

最好的选择是创建一个构造函数参数并放弃将集合初始化器用于它不适合的东西的想法。

【讨论】:

  • 感谢您的回答和解释,如果在内部调用Add,则不能将其与现有列表一起使用是有道理的。
  • 嗯,它适用于TheList = { existingList[0] }。但这是现有列表中的一项。
  • 您可以向类添加一个方法,如果列表为空,则允许初始化列表(但这仍然需要属性的私有设置器)
  • 有很多选择。构造函数就是为此目的,所以使用它。
【解决方案2】:

有没有办法首先正确初始化 List 来创建对象(当然不添加构造函数)?

没有

不是。这就是构造函数所做的。如果你不想在构造函数中做,那就没办法了。

【讨论】:

  • 当然可以,但是由于可以像TheList = {"A", "B"} 一样进行初始化,所以我认为可能有一种方法可以在不触及构造函数的情况下执行此操作。无论如何感谢您的回答!
  • 我想这取决于你所说的“初始化”是什么意思。构造函数正在初始化,之后它只是可以调用的附加代码......与否,这取决于类的用户。如果您不想更改原始签名,则可以有多个构造函数。
【解决方案3】:

无法从类本身外部初始化只读属性。

collection initializer 只是一个简化的语法版本,并不意味着使用这种语法你可以像在类构造函数中一样拥有相同的访问权限

 thirdHolder.TheList = existingList; // this is the traditional way

也许你可以像这样使用工厂类模式

   internal class Program
{
    public static void Main(string[] args)
    {
        // Compiles, but is not what I need
        var firstHolder = new Holder()
        {
            TheList = { "A", "B" }
        };

        // Compiles, but initializes the list after object creation
        var existingList = new List<string>() { "Foo", "Bar" };
        var secondHolder = new Holder();
        secondHolder.TheList.AddRange(existingList);

        // Does not compile
        //var thirdHolder = new Holder()
        //{
        //    TheList =  existingList 
        //};

        //thirdHolder.TheList = existingList; // this is the traditional way
        var thirdHolder = Holder.HolderFactory(existingList);
    }
}


internal class Holder
{
    public Holder()
    {
        TheList = new List<string>();
    }

    public static Holder HolderFactory(List<string> theList)
    {
        return new Holder(theList);
    }
    private Holder(List<string> theList)
    {
        this.TheList = theList;
    }
    public List<string> TheList { get; }
}

【讨论】:

  • 我以为构造函数是类的工厂方法?
  • 不同的是,工厂方法和构造函数的目的是一样的。它用于初始化类。对于简单的初始化场景,可以在构造函数上使用它,但对于复杂的初始化,您最好使用工厂方法。看到这个链接stackoverflow.com/questions/1519358/…
猜你喜欢
  • 2010-09-25
  • 1970-01-01
  • 1970-01-01
  • 2011-12-14
  • 1970-01-01
  • 2011-03-04
  • 1970-01-01
  • 2020-05-11
  • 1970-01-01
相关资源
最近更新 更多