有没有一种方法在C#中创建匿名结构体?

38

似乎没有办法将匿名类型派生自对象。但是我还是想问一下,因为我们在简单的查询表达式中经常使用匿名类型来提取数据子集以用于创建这些匿名类型。对我来说,它们应该是结构体(值类型),以实现更大的内存效率而不是引用类型。

有什么想法?


这将是匿名类不可取的情况下的理想替代品,因为 GC 峰值不受欢迎。 - M-Pixel
4个回答

32

目前没有受支持的C#语法可生成匿名结构体。


3
截至 C# 7.0 版本,这就是情况。考虑到未来可能会发布新的语法版本(比如 7.2、8.0),我觉得注明一个版本号会更好,以防这个答案在未来过时。请注意,翻译不改变原意。 - M-Pixel

23

更新:C# 7现在有值类型元组,可以像引用类型匿名类型一样在相同的上下文中使用。


有人普遍认为值类型比引用类型“更有效率”。这完全是个神话;它们在某些操作上更有效率,在其他操作上则不如引用类型。

例如,如果你所关心的工作单元是“将值复制到新位置”,那么大型值类型与引用类型相比就不那么有效率。引用类型会复制一个指针大小的引用,而不管所引用数据的大小,并因此在单个高度优化的机器指令中进行复制。值类型每次都要复制数据的大小,可能非常大,并且需要多条指令。

不过,匿名类型只是一种方便的功能。如果你不喜欢它们的性能特点,你可以定义自己的结构体。


21
抱歉,Eric。这个问题可以更加优雅一些。我完全明白这与上下文相关。在处理更复杂的功能时,人们必须始终使用智慧来选择值类型和引用类型。但我所见过的大多数匿名类型示例都在不断创建和销毁小型对象实例(具有3到5个成员值左右);该对象仅用作堆第0代上简单数据的传输。这显然比在堆栈上执行此操作更加耗费。我喜欢匿名类型的简洁方便性。但能够在引用类型和值类型之间进行选择仍然是很好的。 - TheHolyTerrah
是的,这是一项方便功能,非常适用于迭代聚合某些信息的临时复合类型,而您不想将其保留在任何其他地方,而只想在当前执行上下文中使用。 - Yuriy Gettya

3
对于许多用例来说,如果实现为公共字段结构体而不是不可变类,则匿名类型和元组将更为高效;一个特定的匿名类型或元组是否更适合作为此类结构体还是不可变类,并不特别取决于其大小,而是取决于它如何使用。如果一个东西永远不会被装箱,使用结构体相对于使用类的成本将取决于大小以及需要复制该东西的次数(请注意,所谓的“不可变”结构体通常需要被复制的次数比公共字段结构体多得多)。如果一个东西在构造后只被复制一两次(在许多使用场景中很常见),则几乎任何大小的公共字段结构体都比不可变类性能更好。另一方面,如果一个东西会经常被强制转换为引用类型,则无论大小如何,不可变类都将大大优于结构体。 强制将结构类型转换为引用类型的成本,以及某些使用情况需要频繁这样做的事实,意味着即使对于大多数临时对象,结构体比不可变类对象更有效率,但使用结构体代替所有内容的效率会低于使用不可变类对象。使用结构体可以提高总体性能10%或更多的用例可能太少,不能证明具有两种不同类型的元组和两种内置匿名类型的成本。需要公开字段结构体的性能优势的代码可以为其确切目的轻松定义结构类型。

0

你是否分析过你的应用程序,并发现匿名类型是其中最慢的部分?如果是这样,我建议你手动创建所需的结构体并重新测试,以查看是否解决了问题。否则,我建议你将更多的时间放在关注手头的业务问题上,而不是花费时间打字(就像该功能允许的那样)。


6
抱歉,我并没有意味着存在任何问题。完全没有。我只是出于原则始终在寻找减轻GC负担的方法。只要有机会把东西放到栈上,我就会这么做。仅用作简单数据传输的简单类型最好放在栈上。 - TheHolyTerrah
4
如果你要从工具箱里选一个工具,只要这个选择本身不浪费时间,那么最好选一个更好的工具。 - Niall Connaughton
这并不回答所提出的问题,应该是一条评论。 - julealgon
宇宙似乎对七年来的事情毫不在意。感谢您继续将Stack Overflow持续地推向无关紧要的状态。 - No Refunds No Returns

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