2011-11-16 23 views
12

我有一个包含两个列表一个struct有没有一种方法来初始化一个struct的成员,而无需使用构造函数?

struct MonthData 
{ 
    public List<DataRow> Frontline; 
    public List<DataRow> Leadership; 
} 

不过,我要来初始化创建结构时。如果我尝试:

struct MonthData 
{ 
    public List<DataRow> Frontline = new List<DataRow>(); 
    public List<DataRow> Leadership = new List<DataRow>(); 
} 

然后我得到:

Error 23 'MonthData.Frontline': cannot have instance field initializers in structs 
... 

由于结构不能有参数构造函数,我不能只设置这个在构造函数中无论是。到目前为止,我只能看到如下选项:

  1. 当我创建MonthData的实例
  2. 使用类,而不是一个结构
  3. 带参数创建一个构造函数和使用初始化两个属性
  4. 让getter和setter方法是初始化它们懒洋洋地 的属性。

,这是什么建议的方法?现在,我想让这个班是最好的主意。

+0

让它成为一个类。一旦将引用类型添加到结构中,它实际上不再是值类型。 – drdwilcox

+1

是否真的可以使它成为引用类型(类)与值类型(结构)?如果是,请继续并将其设为一堂课。 – BoltClock

+0

是的,这种类型是一个结构是没有意义的。 –

回答

7

你应该使用一个类来代替。从MSDN

一般来说,类用于建模更复杂的行为,或者创建一个类对象之后被修改的意图的数据。结构最适合小数据结构,主要包含在创建结构后不打算修改的数据。

1

没有办法用一个构造函数来做到这一点。 CLR可以并将创建结构实例,只需简单地初始化内存并避免任何开销。但是,您可以利用这些知识并创建具有相同可观察效果的延迟初始化属性。

例如:

struct MonthData { 
    private bool m_initialized; 
    private List<DataRow> m_frontLine; 
    private List<DataRow> m_leaderShip; 

    public List<DataRow> FrontLine { 
    get { 
     EnsureInitialized(); 
     return m_frontLine; 
    } 
    } 

    public List<DataRow> LeaderShip { 
    get { 
     EnsureInitialized(); 
     return m_leaderShip; 
    } 
    } 

    void EnsureInitialized() { 
    if (!m_initialized) { 
     m_initialized = true; 
     m_frontLine = new List<DataRow>(); 
     m_leaderShip = new List<DataRow>(); 
    } 
    } 
} 
+0

是的,我认为做这样的事情将是我的第二选择。但它是一个如此简单的对象,我倾向于同意这里的其他人,并认为这应该只是一个类 - 尤其是因为它只包含两个引用类型。 –

+1

@MikeChristensen是的,它应该可能是一个班。我的答案更多的是“如果你被困在一个角落,必须使用一个结构,然后做到这一点” – JaredPar

+0

是的,我认为工厂方法和懒惰初始化方法非常酷 - 我会记住这些以应对未来的设计挑战。 –

6

如果你只是问语法...尝试建立和使用静态工厂,而不是...一般情况下,结构应使用的东西是不可改变的,并一个工厂,(它调用私有构造函数)是一个不变的类型比使用公共构造一个更好的办法。

struct MonthData 
    {  
     public List<DataRow> Frontline; 
     public List<DataRow> Leadership; 
     private MonthData(List<DataRow> frontLine = null, 
         List<DataRow> leadership = null) 
     { 
     Frontline = frontLine?? new List<DataRow>(); 
     Leadership = leadership?? new List<DataRow>(); 
     } 
     public static MonthData Factory(
      List<DataRow> frontLine= null, 
      List<DataRow> leadership= null) 
     { return new MonthData(frontLine, leadership); } 
    } 
+0

这绝对是一个有趣的方法,正如你所提到的,我的对象并不是不可变的(它更像是一个集合,它的生活)所以也许一个班级是最好的。虽然这个想法+1。 –

+0

我喜欢静态工厂方法的想法。但是,你可以结构中没有实例字段初始值设定项。所以'公开名单 FrontLine =新名单()'不会编译。 –

+0

@Jim Mis,是的,剪切和粘贴没有编辑...修复它... –

6

你在你的结构使用引用类型(List<T>)反正,因此结构作为值类型的使用就没有任何意义了我。我只是去上课。

+0

另一种替代方法是使用'ImmutableArray '并使用@CharlesBretana提到的构建器方法。 – m93a

1

这本来是很好,如果CLR已经让低保结构类型的东西可能会对他们进行一些初始化代码运行它们变得可见,以这样的代码以外的任何东西之前的一种手段。这本来是能够做到这一点,建立一个结构类型的数组即使当,通过向阵列本身的任何地方暴露的基准之前通过引用具有CLR通阵列的所有的单个元素。不幸的是,如果在创建数组期间抛出异常,它会导致一种尴尬的情况。如果构造函数没有任何副作用,那么就没有问题 - 只需放弃数组并假装即使成功创建的对象也不存在。但是,带有副作用的建设者可能会造成一些困难。

但是,在构造时没有办法初始化结构,因此没有很好的方法来实现需要初始化的对象的值类型语义。抱歉。即使值类型语义更适合您的类型(如果情况比某些人认为的要多得多),如果需要初始化,您将不得不使用引用类型。对结构进行延迟初始化并不实际。例如,如果有一个字典<字符串,MonthData >调用MyDict,则重复访问MyDict(“George”)。FrontLine会分别生成一个新的List。讨厌。

可变的结构不是邪恶的;如果有的话,我是他们更强大的倡导者之一。尽管如此,.NET在处理可变结构方面存在一些限制,因此很多情况下值类型的语义都是合适的,但.net的限制使得不能正确地提供这样的语义。

相关问题