寻找一种在C#中初始化大型对象列表的更好方法

时间:2013-03-15 21:56:49

标签: c#

new List<BaseType>
{
    new DerivedType
    {
        x="x1",y="y1",z="z1"
    },
    new DerivedType
    {
        x="x2",y="y2",z="z2"
    },
    new DerivedType
    {
        x="x3",y="y3",z="z3"
    },
    new DerivedType
    {
        x="x4",y="y4",z="z3"
    },
    ...
}

在静态方法中,通过上面的方法初始化列表,我想知道是否有更好的方法在语法上做这个。

每次都以相同的顺序设置相同的字段,以便更容易。

6 个答案:

答案 0 :(得分:8)

为什么不在这里使用for循环?

var list = new List<BaseType>(SomeValue);
for (int i = 1; i < SomeValue; i++) { 
  list.Add(new DerivedType {
    x = string.Format("x{0}", i),
    y = string.Format("y{0}", i),
    z = string.Format("z{0}", i)
  });
}

注意:我假设示例代码中的最后一个init应该有"z4"而不是"z3"

答案 1 :(得分:5)

如果值实际上“x1”等,那么:

var list = Enumerable.Range(1, n)
                     .Select(i => new DerivedType {
                                 x = "x" + i,
                                 y = "y" + i,
                                 z = "z" + i
                             })
                     .ToList<BaseType>();

这取决于C#4中的协方差。在C#3(或针对.NET 3.5)中,你需要类似的东西:

var list = Enumerable.Range(1, n)
                     .Select(i => (BaseType) new DerivedType {
                                 x = "x" + i,
                                 y = "y" + i,
                                 z = "z" + i
                             })
                     .ToList();

或者如果那些只是样本值(或者即使它们不是),只需将构造函数添加到DerivedType以允许您一次性传递三个属性将减少混乱:

new List<BaseType>
{
    new DerivedType("x1", "y1", "z1"),
    new DerivedType("x2", "y2", "z2"),
    new DerivedType("x3", "y3", "z3"),
    new DerivedType("x4", "y4", "z4"),
    ...
}

答案 2 :(得分:2)

您可以创建List<T>的子类:

public class BaseTypeList : List<BaseType>
{
    public void Add(string x, string y, string z)
    {
        Add(new DerivedType { x = x, y = y, z = z });
    }
}

然后您可以更简洁地使用集合初始化程序语法:

new BaseTypeList
{
    { "x1", "y1", "z1" },
    { "x2", "y2", "z2" },
    { "x3", "y3", "z3" },
    { "x4", "y4", "z3" /* (sic) */ },
    //...
}

这是有效的,因为编译器为集合初始化程序块中的每个元素执行单独的重载解析,查找具有与给定参数匹配的参数类型的Add方法。

如果你需要同类衍生类型,它会有点难看,但它是可能的:

public class BaseTypeList : List<BaseType>
{
    public void Add(Type t, string x, string y, string z)
    {
        Add((BaseType)Activator.CreateInstance(t, x, y, z));
    }
}

然后你会像这样初始化集合:

new BaseTypeList
{
    { typeof(DerivedType1), "x1", "y1", "z1" },
    { typeof(DerivedType1), "x2", "y2", "z2" },
    { typeof(DerivedType2), "x3", "y3", "z3" },
    { typeof(DerivedType2), "x4", "y4", "z3" /* (sic) */ },
    //...
}

答案 3 :(得分:1)

使用NBuilder,您需要一行或两行代码(可以从NuGet获取):

List<BaseType> list = Builder<DerivedType>.CreateListOfSize(5).Build()
                                          .ToList<BaseType>();

它使用值"xN" "yN" "zN"(属性名称+元素索引)初始化所有属性。

答案 4 :(得分:1)

我觉得奇怪的是,没有人解决OP更普遍的问题,而是专注于该例子的人为特例。

正如所有重击手在这里所注意到的,对于这个例子的具体情况,正如Perl修道者可能会说的那样,“TMTOWTDI” - 有多种方法可以做到这一点。比其他人更好(或至少更简洁)。

在更一般的情况下,事情不是所有的单调序列,我认为没有更好的东西。你遇到了很多重复的样板。

C#没有像JSON或Javascript的对象初始化器那样的东西,或者C compound literals(2000年用C99引入),所有这些都为这类东西提供了更为简洁的语法。如果你问我,可惜。

这是一个想法,虽然有点丑陋的黑客:SCG.List<T>和许多其他SCG集合有一个构造函数重载接受IEnumerable<T>IDictionary<TKey,TValue>或其他东西类似于正在构建的对象的填充。可以想象,可以将方式中所需的数据作为 embedded resource 以适合您的目的的格式嵌入。它甚至不必是一个嵌入式资源:一个简单的多行字符串文字,每个项目有一个逗号分隔的行就可以了。提供一个简单的工厂类或方法,使用该资源生成一个可以传递给IEnumerable构造函数和Bob's-Yer-Uncle的LINQy List<T>小部件流。

就像我说的,有点丑陋的黑客,但它会避免重复输入。

答案 5 :(得分:0)

我会用一个简单的数组来保存数据。然后使用此数组构建派生类型。请注意,数据值可能有些任意(此处显示的是字符串和int类型)。只需使用一个字符串数组就可以优化原始问题。

object[] data = 
{
    "x1", "y1", 4,
    "x2", "y2", 3,
    "x3", "y3", 2,
    "x4", "y4", 3
};

int countPerType = 3;
int size = data.Length;

var initMe = new List<BaseType>();

for (int idx = 0; idx < size; idx += countPerType)
{
    initMe.Add(
        new DerivedType() 
        { 
            X = (string)data[idx], 
            Y = (string)data[idx + 1], 
            Z = (int)data[idx + 2] 
        });
}