在 List<T> 中添加 List<DateTime> 值

4
这可能有点棘手。基本上,我有一个类,看起来像这样:
class Timer
{
    public string boss { get; set; }
    public List<DateTime> spawnTimes { get; set; }
    public TimeSpan Runtime { get; set; }
    public BossPriority priority { get; set; }

}

正如您所看到的,我想在我的对象中添加一个DateTime列表。因此,我创建了一个类似于以下列表的列表:

List<Timer> bosses = new List<Timer>();

我希望我能做类似的事情,添加日期时间:
bosses.Add(new Timer { boss = "Tequatl", priority = BossPriority.HardCore, spanTimes = {  DateTime.ParseExact("07:00 +0000", "hh:mm zzz", CultureInfo.InvariantCulture) } });

不幸的是,这给了我一个"对象引用未设置为对象实例"的错误。

像这样做也没有任何区别 :(

Timer boss = new Timer();
DateTime t1 = DateTime.ParseExact("07:00 +0000", "hh:mm zzz", CultureInfo.InvariantCulture);
DateTime t2 = DateTime.ParseExact("11:30 +0000", "hh:mm zzz", CultureInfo.InvariantCulture);
boss.spawnTimes.AddRange(new List<DateTime> { t1, t2 });

我是否真的需要在每个 DateTime 上执行 .Add() 操作?

6个回答

5

你的NRE是由于没有初始化Timer.spawnTimes引起的。

如果将该类初始化为默认构造函数的一部分,则可以节省输入:

public class Timer {

    public List<DateTime> SpawnTimes { get; private set; }
    ...

    public Timer() {
        this.SpawnTimes = new List<DateTime>();
    }

}

另一种选择是拥有一个重载的构造函数,接受 params 参数:

public class Timer {

    public List<DateTime> SpawnTimes { get; private set; }
    ...

    public Timer() {
        this.SpawnTimes = new List<DateTime>();
    }

    public Timer(String boss, /*String runtime,*/ BossPriority priority, params String[] spawnTimes) : this() {

        this.Boss = boss;
//      this.Runtime = TimeSpan.Parse( runtime );
        this.Priority = priority;

        foreach(String time in spawnTimes) {

            this.SpawnTimes.Add( DateTime.ParseExact( time, "HH:mm" ) );
        }

    }
}

实际应用中通常这样使用:

bosses.Add( new Timer("Tequat1", BossPriority.HardCore, "07:00 +0000" ) );
bosses.Add( new Timer("Tequat2", BossPriority.Nightmare, "01:00 +0000", "01:30 +0000" ) );
bosses.Add( new Timer("Tequat3", BossPriority.UltraViolence, "12:00 +0000" ) );

同时:FxCop/StyleCop 时间到了!

  • 类型(如类)应该使用 PascalCase
  • 公共成员也应该使用 PascalCase(与 Java 不同,Java 中使用的是 camelCase
    • 例如: public BossPriority priority 应该改为 public BossPriority Priority
  • 集合成员不应通过可变属性暴露(即使用 private set 而不是 set(隐含 public)
  • 公共集合成员应该是 Collection<T>ReadOnlyCollection<T> 而不是 List<T>T[]

1
这绝对是我首选的选项。它的额外好处在于,如果构造一个 Timer 时没有显式地构造/分配一个 List<DateTime> 对象,那么您以后就不必处理 null 引用。也就是说,var t = new Timer(); t.SpawnTimes.Add(...); 是可以的。此外,您可以自信地迭代任何 Timer 实例,而无需先执行 null 检查。最后,它使您的代码更简单,因为您不必在每个实例化 Timer 的地方都复制 List<DateTime> 构造。 - Chris Sinclair
1
@GrantWinney:不,spawnTimes = { DateTime.... } 语法会为在构造期间分配的 List 上的每个项调用 Add 方法。这不会覆盖 SpawnTimes 实例。编辑:仅当你有 spawnTimes = new List<DateTime> { DateTime.Parse...} 时才会覆盖。 - Chris Sinclair
1
@GrantWinney:是的,这在文档中有点难找。C# 3.0 概述中的“26.4.2 集合初始化器”一节提供了一个示例。我认为相关行为的声明也在同一页的第26.4节中:“在等号后指定集合初始化器的成员初始化器是嵌套集合的初始化。与将新集合分配给字段或属性不同,初始化器中给出的元素将添加到由字段或属性引用的集合中。” - Chris Sinclair

2

你已经接近了... 你只是忘记声明一个新实例。

加上new[],然后将数组转换为List

bosses.Add(new Timer { boss = "Tequatl", priority = BossPriority.HardCore,
    spawnTimes = new[] { DateTime.ParseExact("07:00 +0000", "hh:mm zzz", CultureInfo.InvariantCulture) }.ToList() });

1
如果你要这样做,最好只是使用 new List<DateTime> { DateTime.ParseExact(....) },而不是创建一个数组,然后将其抛弃以创建一个 List。另外,这并不是将数组“转换”为列表;它是创建一个新列表,并将元素复制到其中。 - Chris Sinclair
是的,我也刚刚检查过了,它也完美地工作了^^。 我将不得不标记那个,抱歉 :) - Jazerix

2

试试这个:

spanTimes = new List<DateTime>{  DateTime.ParseExact("07:00 +0000", "hh:mm zzz", CultureInfo.InvariantCulture) }

基本上,使用列表初始化语法用所需的值初始化新列表。


2
bosses.Add(new Timer { boss = "Tequatl", priority = BossPriority.HardCore, spanTimes = new List<DateTime> {  DateTime.ParseExact("07:00 +0000", "hh:mm zzz", CultureInfo.InvariantCulture) } });

您需要使用new创建您的spawnTimes


1

在使用之前,您需要初始化spawnTimes集合

boss.spawnTimes = new List<DateTime>();

1
你已经接近了,但需要包括List实例化。尝试:
bosses.Add(new Timer { boss = "Tequatl", priority = BossPriority.HardCore, spanTimes = new List<DateTime>{ DateTime.ParseExact("07:00 +0000", "hh:mm zzz", CultureInfo.InvariantCulture) } });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接