1
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"
    },
    ...
}

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

每次都以相同的顺序设置相同的字段,以防万一。

4

6 回答 6

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"

于 2013-03-15T21:58:48.103 回答
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"),
    ...
}
于 2013-03-15T22:01:34.640 回答
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) */ },
    //...
}
于 2013-03-16T01:18:28.407 回答
1

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

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

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

于 2013-03-15T22:03:28.597 回答
1

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

正如这里所有重量级人物所注意到的那样,对于示例的特定情况,正如 Perl 苦行者可能会说的那样,“ TMTOWTDI ”——有不止一种方法可以做到这一点。有些比其他更好(或至少更简洁)。

在更一般的情况下,事情并不全是单调序列,我认为没有比这更好的了。你被很多重复的样板卡住了。

C# 没有 JSON 或 Javascript 的对象初始值设定项或 C 的复合文字(2000 年随 C99 引入),所有这些都为这类事情提供了更简洁的语法。很遗憾,如果你问我。

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

就像我说的那样,有点丑陋,但它可以避免重复输入。

于 2013-03-15T23:52:20.097 回答
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] 
        });
}
于 2013-03-15T22:57:03.710 回答