何时一个结构体太大?

5

可能重复:
C#中结构体与类的区别

如果我的结构体太大,是否会影响效率,这个问题可能没有定论。我想使用结构体是因为我了解到它们比类更快,而且我确实需要速度。

我发现如果结构体太大,实际上会减慢程序的运行速度,所以我想知道有关这方面的指导方针,以及是否需要将我的结构体转换成类。

public struct Tiles
{
    public Rectangle rect;

//i know this wont run with them being initalized like this but if i change to a class this will 
//stay like this and im in the middle of deciding what to do

    Bitmap currentPic = new Bitmap(50, 50);
    ImageAttributes imgAttr = new ImageAttributes();
    float[][] ptsArray;
    ColorMatrix clrMatrix;

    public void setTiles(int i, int k, int width, int height)
    {
        Rectangle temp = new Rectangle(i, k, width, height);
        rect = temp;

        float[][] ptsTemp ={
         new float[] {1, 0, 0, 0, 0},
         new float[] {0, 1, 0, 0, 0},
         new float[] {0, 0, 1, 0, 0},
         new float[] {0, 0, 0, .9f, 0},
         new float[] {0, 0, 0, 0, 1}};

        ptsArray = ptsTemp;
        clrMatrix = new ColorMatrix(ptsArray);
        currentPic = The_Great_Find__Dig_Deeper.Properties.Resources.darknessflashlight;
    }

    public void setTransperancy(float value)
    {
        clrMatrix.Matrix33 = value;
    }

    public void drawRect(Graphics g)
    {
        imgAttr.SetColorMatrix(clrMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

        g.DrawImage(currentPic, rect, 0, 0, currentPic.Width, currentPic.Height, GraphicsUnit.Pixel, imgAttr);
    }

    bool blackened
    {
        get;
        set;
    }
}

我应该将它改成一个类吗?对我来说它变得有点臃肿了。我正在使用Visual Studio 2008。


2
它看起来不臃肿,但很凌乱。缩进也很凌乱。在Visual Studio中,您可以使用Ctrl+K+D来解决这个问题。 - BoltClock
15
结构体并非普遍比类更快,没有任何魔法可以使其如此。在许多情况下,结构体会更慢。如果你不理解结构体的工作原理,它们也可能会给你带来意外惊喜。一般来说,我建议使用类。 - Matt Greer
我猜我会将它改为一个类。对于重复的主题,抱歉。 - Bigfatty
2
使用性能分析工具来测量您的性能,然后根据事实进行优化,而不是像您现在这样猜测。通过疯狂地猜测,您永远无法获得良好的性能。 - Eric Lippert
我建议在结构体中,任何持有对可变类的引用的字段都应该是只读的,并且应该被实例化以持有新的对象实例(尽管使用默认构造函数创建一个这些字段为空白的结构体是可以的,但创建有效的结构体的唯一方法是使用将初始化这些字段的构造函数)。 - supercat
4个回答

8

建议给非黑带程序员:不要对你的代码进行优化。

建议给黑带程序员:稍后再优化你的代码。

认真建议你听取这个建议!

为了给你一些更相关的解释,你应该知道,与类不同,结构体在栈上分配,而不是在堆上。 栈分配略微便宜,但通常仅适用于小的对象,这些对象或者短命,或者按值传递,或者将存储在大型数组中。

如果你不知道按值传递意味着什么,那就意味着每当你将其作为参数传递给方法时,整个结构体都会被复制。 如果你的结构体不是非常小,这可能很快变得非常昂贵。 如果你不理解这个区别,那么它也可能导致意外行为:在方法中对参数所做的更改对方法调用者可见; 在方法中对结构体参数所做的更改则对方法调用者可见(因为该方法正在更改原始数据的副本)。

重申我的第一个观点:不要使用结构体,除非你确信自己知道在做什么。

希望这有所帮助!


这真的帮了很多。感谢你为我分解它。 - Bigfatty
9
结构体(structs)被分配在栈上,而不是堆上。这是一种常见的错误。在CLR中,值类型(structs)的分配行为要复杂得多。请参考:https://dev59.com/J2445IYBdhLWcg3wcaAN#4853251 - LBushkin
5
某物的种类决定其分配位置的整个想法本身就是荒谬的。显然,某物是在短寿命存储器(栈)还是长寿命存储器(堆)中分配取决于它的生命周期,而不是存储是按值还是按引用复制。 - Eric Lippert
6
结构体不能合理地说是在栈上分配的。作为静态字段、实例字段、匿名函数的闭合局部变量、迭代块的局部变量或数组内的结构体都不会在栈上分配。被优化到寄存器中的结构体也不会在栈上分配。此外,大家经常忘记了引用!引用的指向对象从来不在栈上,但引用本身经常在栈上。为什么大家总是忘记引用?它们可以占用大量的栈,或者寄存器。 - Eric Lippert
5
此外,你主张堆栈分配更“廉价”的观点似乎有待商榷。为什么通过移动堆栈指针进行分配比通过移动GC堆指针进行分配更昂贵或更便宜呢?开销不在于堆分配,而在于堆分配的副作用——收集压力,这会导致更频繁的垃圾回收。 - Eric Lippert
显示剩余3条评论

3

如果只是考虑大小,那么选择结构体而不是类并没有必要。只有当您需要值语义时才使用结构体。可以想象一下int类型,5就是5,引用并不重要。结构体总是通过复制方式传递。

如果需要值语义,请使用结构体。否则,请使用类。


2
预先优化是万恶之源,这就是常言道的。先构建你的应用程序,只有在它出现性能问题时才尝试修复它们。例如,一种方法可能运行速度比另一种方法慢两倍,但你可以将第一种并行化,并同时运行4次。因此,第一种方法实际上更快。你必须完全了解你的性能问题才能修复它。回答你的问题:据我回忆,当传递到方法中的结构体大小为16字节或更大时,它比类更慢。

16个字节:http://msdn.microsoft.com/en-us/library/ah19swz4(v=vs.71).aspx - Liviu Trifoi
1
这段时间我通常总是试图想出最有效的编程方法,然后去实现它,但现在我想我只会先编程,如果必要的话再进行优化。感谢您的建议。 - Bigfatty

1

请问您能否定义“速度”?

如果使用类运行程序需要10秒,而使用结构体相同的程序只需要9.4秒,这是否加快了程序的速度或者说这是可以想象的速度?

您还需要记住,与引用类型相比,复制结构体将需要更长的时间。

您是唯一能够确定结构体或类是否适合您目的的人。

如果:

  1. 对象很小。
  2. 在逻辑上是不可变的。

那么请使用结构体。

如果我是您,我会使用分析器来准确地知道程序在哪里运行缓慢。

据我所知,使用结构体而不是类无法实现可想象的改进。


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