将结构类型成员公开为属性而不是字段通常会产生较差的性能和语义,尤其是在结构实际上被视为结构而不是“古怪对象”的情况下。
.NET中的结构是通过管道方式捆绑在一起的字段的集合,可以出于某些目的将其视为一个单元。.NET Framework旨在允许使用与类对象几乎相同的方式来使用结构,有时这可能很方便。
围绕结构的许多建议是基于这样的观念,即程序员将要使用结构作为对象,而不是将它们作为磁带的字段集合。另一方面,在许多情况下,将某些行为表现为一束束缚在一起的字段可能会很有用。如果这是需要的,.NET建议将为程序员和编译器增加不必要的工作,与直接使用结构相比,产生的性能和语义更糟。
使用结构时要记住的最大原则是:
不要按值传递或返回结构,否则会导致不必要的复制。
如果坚持原则1,那么大型结构的性能将与小型结构相同。
如果Alphablob
是含有26个公共的结构int
命名为AZ域和属性的getter ab
返回其总和a
和b
字段,然后给定Alphablob[] arr; List<Alphablob> list;
的代码int foo = arr[0].ab + list[0].ab;
需要阅读领域a
和b
的arr[0]
,但将需要阅读的所有26场list[0]
,即使它会忽略其中的两个。如果希望拥有一个通用的类似列表的集合,并且可以使用像这样的结构有效地工作alphaBlob
,则应该使用以下方法替换索引的getter:
delegate ActByRef<T1,T2>(ref T1 p1, ref T2 p2);
actOnItem<TParam>(int index, ActByRef<T, TParam> proc, ref TParam param);
然后将调用proc(ref backingArray[index], ref param);
。给定这样一个集合,如果将其替换sum = myCollection[0].ab;
为
int result;
myCollection.actOnItem<int>(0,
ref (ref alphaBlob item, ref int dest)=>dest = item,
ref result);
这样就避免了需要复制alphaBlob
不会在属性getter中使用的部分。由于传递的委托除了访问其ref
参数外不访问任何其他内容,因此编译器可以传递静态委托。
不幸的是,.NET Framework并未定义使该程序正常运行所需的任何类型的委托,并且语法最终变得一团糟。另一方面,这种方法可以避免不必要的复制结构,这反过来又使对数组中存储的大型结构执行就地操作成为可能,这是访问存储的最有效方法。