为什么要创建对象的本地版本? [英] Why should I create a local version of an object?

查看:60
本文介绍了为什么要创建对象的本地版本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

嗨!


在PaintEventArgs.Graphics属性的两个示例之一(在

VS 2005文档中),Graphics-object被保存的是在使用之前,到本地

变量。在另一个例子中,没有这样的保存是完成的。为什么Graphics-object保存在其中一个示例中?那是

真的有必要吗?


示例#1:


private void pictureBox1_Paint(object sender,

System.Windows.Forms.PaintEventArgs e)

{

//为PictureBox创建图形对象的本地版本。

Graphics g = e.Graphics;


//在PictureBox上画一个字符串。

[snip]

//在PictureBox中画一条线。

[snip]

}


示例#2:


//直接使用e.Graphics而不创建本地版本...

private void Form1_Paint(对象发送者,

系统.Windows.Forms.PaintEventArgs e)

{

//画出矩形......

e.Graphics.DrawRectangle(new Pen( Color.Blue,PenWidth),RcDraw);

}

Hi!

In one of the two examples for the PaintEventArgs.Graphics-property (in
the VS 2005 documentation), the Graphics-object is "saved" to a local
variable, before being used. In the other example, no such saving is
done. Why was the Graphics-object saved in one of the examples? Is that
really necessary?

Example #1:

private void pictureBox1_Paint(object sender,
System.Windows.Forms.PaintEventArgs e)
{
// Create a local version of the graphics object for the PictureBox.
Graphics g = e.Graphics;

// Draw a string on the PictureBox.
[snip]
// Draw a line in the PictureBox.
[snip]
}

Example #2:

// Uses e.Graphics directly without "creating a local version"...
private void Form1_Paint(object sender,
System.Windows.Forms.PaintEventArgs e)
{
// Draw the rectangle...
e.Graphics.DrawRectangle(new Pen(Color.Blue, PenWidth), RcDraw);
}

推荐答案

" matko" <毫安***** @ gmail.com>在消息中写道

news:11 ********************* @ g43g2000cwa.googlegro ups.com ...
"matko" <ma*****@gmail.com> wrote in message
news:11*********************@g43g2000cwa.googlegro ups.com...
//为PictureBox创建图形对象的本地版本。
图形g = e.Graphics;
// Create a local version of the graphics object for the PictureBox.
Graphics g = e.Graphics;




如果没有代码工作方式的巨大差异,但它节省了一些时间,因为你不必从

中检索Graphics对象事件args over和结束。


Michael



If doesn''t make a huge difference in the way in which the code works but it
saves some time because you don''t have to retrieve the Graphics object from
the event args over and over.

Michael


matko,一个Graphics对象是一个类的实例(不是结构)所以它是一个

参考类型。因此,代码如下:


图形g = e.Graphics;


....不会复制图形对象 - 它复制对该对象的引用。

至少在调试模式下,这将为您提供轻微的性能提升,因为

它可以避免任何后续调用属性getter (这实际上是IL中的一个

函数调用,具有特殊名称get_Graphics的方法)。


在发布模式下,优化是通常启用后,C#或JIT

编译器可能会决定缓存结果值。这一切都取决于

编译器是否知道 Graphics属性在每次调用Paint事件处理程序时返回一个不变的
结果,以及

优化器是否决定缓存该值是堆栈内存的最佳使用或者

可用的注册表。


- 最好的问候
matko, a Graphics object is an instance of a class (not a struct) so it is a
reference type. As a result, code such as this:

Graphics g = e.Graphics;

.... doesn''t copy the Graphics object--it copies a reference to that object.
In Debug mode at least, this will give you a slight performance boost since
it avoids any subsequent calls to the property "getter" (which is actually a
function call in IL, to a method with the special name "get_Graphics").

In Release mode, where optimization is normally enabled, the C# or JIT
compiler may decide to cache the result value anyway. It all depends on
whether the compiler "knows" that the Graphics property returns an invariant
result within each invocation of a Paint event handler, and on whether the
optimizer decides that caching that value is the best use of stack memory or
an available register.

--best regards


matko,
matko,
在PaintEventArgs.Graphics属性的两个示例之一中(在VS 2005文档中),Graphics-object被保存了。在使用之前,到本地
变量。在另一个例子中,没有完成这样的保存。为什么Graphics-object保存在其中一个示例中?这是非常必要的吗?
In one of the two examples for the PaintEventArgs.Graphics-property (in
the VS 2005 documentation), the Graphics-object is "saved" to a local
variable, before being used. In the other example, no such saving is
done. Why was the Graphics-object saved in one of the examples? Is that
really necessary?




我有一个故事要讲 - 有数据。我希望不会吓到任何人。


matko提出的问题至少有两个方面; 1)风格和2)

表现。在编写

生产代码时,样式是第一个最重要的方面。你(和你的团队)应该选择一种风格,然后确保

所有代码都遵循这种风格。只要代码存在,所有代码都以相同的样式写成

将具有不可测量的价值。


在某些时候,性能可能会成为一个问题对于代码的某些部分。

但是第一印象是骗人的;特别是在这种情况下。


为了说明这一点,我在MS VisualStudio 2005中整理了一个项目

(Beta 2发布),它显示了两者之间的性能差异1)直接

访问,2)通过属性访问,3)通过getter访问和4)

从getter中检索的缓存值。我将在这篇文章的末尾包含代码。

请注意,我在2.8GHz HP Pentium 4笔记本电脑上运行代码。

代码在一个循环中增加3和5,循环次数为1000000000次。使用Debug构建在IDE中运行代码时得到的

输出是:


[使用来自getters的缓存值访问]总和为:8000000000 in :

00:00:12.6093750秒。

[使用getter访问]总和为:8000000000 in:00:00:53.2031250 sec。

[使用属性访问]总和为:8000000000 in:00:00:38.1093750 sec。

[直接访问]总和为:8000000000 in:00:00:07.3750000 sec。


[直接访问]总和为:8000000000 in:00:00:07.3281250 sec。

[使用属性访问]总和为:8000000000 in:00:00: 37.8437500秒。

[使用getter访问]总和为:8000000000 in:00:00:53.1562500 sec。

[使用getters中的缓存值访问]总和为: 8000000000 in:

00:00:12.5625000 sec。


请注意,我按照给定的顺序运行了两次代码,然后是另一个代码

时间以相反的顺序作为完整性检查。此输出显示直接

访问速度几乎是其他方法中最好的两倍。如何在IDE中运行调试代码有多大影响?生成的

输出是通过从命令提示符运行Debug构建获得的:


00:00:12.5937500秒。

[使用getter访问]总和为:8000000000 in:00:00:45.5937500 sec。

[使用属性访问]总和为:8000000000 in:00:00:36.9843750 sec。

[直接访问]总和为:8000000000 in:00:00:07.2968750 sec。


[直接访问]总和为:8000000000 in:00:00:07.2968750 sec。

[使用属性访问]总和为:8000000000 in:00:00:37.1093750 sec。

[使用getter访问]总和是:8000000000 in:00:00:46.1406250 sec。

[使用getters中的缓存值访问]总和为:8000000000 in:

00:00:12.5781250 sec。


我们可能期望结果会变得更好,因为有

没有IDE开销。有趣的是,表现最差的人最多改善了
。此输出显示直接访问仍然是明显的表现

获胜者。现在从

a命令提示符运行Release版本时检查输出:


[使用getters中的缓存值进行访问]总和为:8000000000 in:

00:00:10.7031250秒。

[使用getter访问]总和为:8000000000 in:00:00:09.7031250 sec。

[访问使用属性]总和是:8000000000 in:00:00:10.6406250 sec。

[直接访问]总和是:8000000000 in:00:00:10.7031250 sec。

[直接访问]总和为:8000000000 in:00:00:10.7031250 sec。

[使用属性访问]总和为:8000000000 in:00:00:10.5937500 sec。

[使用getter访问]总和是:8000000000 in:00:00:09.6875000 sec。

[使用getters中的缓存值访问]总和为:8000000000 in:

00:00:10.7031250秒。


哇 - 它们几乎等同,最糟糕的是调试。表演者比其他方法略微优于
。明白了吗。在判断代码性能时,第一印象可能是欺骗性的。对于

生产代码,基本上没有性能权衡选择

一种访问另一种风格的情况类似于示例代码我

跑了。不要相信任何告诉你性能影响的人。


选择最适合你和你的团队的编码风格,然后按照它进行操作。

一旦你有一个应用程序一直

遵循你已经测量并确定了真正的b
性能瓶颈的风格,就会担心性能。


兰迪


示例代码如下:

===== ============================================= ====

使用系统;


名称空间CachedVariableProfile

{

公共类计划

{

static void Main(string [] args)

{

testWithCachedGetterValues();

testWithAccessUsingGetters ();

testWithAccessUsingProperties();

testWithDirectAccess();


testWithDirectAccess();

testWithAccessUsingProperties();

testWithAccessUsingGett ers();

testWithCachedGetterValues();

}


public static void testWithAccessUsingProperties()

{

Container dataSupplier = new Container(3,5);

long sum = 0;


DateTime endTime;

DateTime startTime = DateTime.Now;


for(int i = 0;我< 10亿; i ++)

{

sum + = dataSupplier.MyValue.X;

sum + = dataSupplier.MyValue.Y;

}


endTime = DateTime.Now;


System.Console.Out.WriteLine(" [使用属性访问]总和

是:" + sum.ToString()+" in:" +(endTime - startTime)+" sec。");

}


public static void testWithAccessUsingGetters()

{

Container dataSupplier = new Container(3,5);

long sum = 0;


DateTime endTime;

DateTime startTime = DateTime.Now;


for(int i = 0; i< 1000000000; i ++)

{

sum + = dataSupplier.getX();

sum + = dataSupplier.getY();

}


endTime = DateTime.Now;


System.Console .Out.WriteLine([使用getters访问]总和是:

" + sum.ToString()+" in:" +(endTime - startTime)+sec。 "); < br $>
}


public static void testWithCachedGetterValues()

{

Container dataSupplier = new Container(3 ,5);

long sum = 0;


DateTime endTime;

DateTime startTime = DateTime.Now;

int x = dataSupplier.getX();

int y = dataSupplier.getY();


for(int i = 0;我< 10亿; i ++)

{

sum + = x;

sum + = y;

}


endTime = DateTime.Now;


System.Console.Out.WriteLine(" [使用来自

的缓存值访问getters]总和是:" + sum.ToString()+" in:" +(endTime - startTime)+

" sec。");

}


public static void testWithDirectAccess()

{

Container dataSupplier = new Container(3,5); < br $>
long sum = 0;


DateTime endTime;

DateTime startTime = DateTime.Now;


for(int i = 0; i< 1000000000; i ++)

{

sum + = dataSupplier.myValue.x;

sum + = dataSupplier.myValue.y;

}


endTime = DateTime.Now;


System.Console.Out.WriteLine(" [Direct Access]总和是:" +

sum.ToString()+" in:" +(endTime - startTime)+"秒。;;

}

}


公共舱容器

{

公共Containee myValue;


public Container(int x,int y)

{

myValue = new Containee(x,y);

}


公共Containee MyValue

{

get

{

返回myValue;

}

}


public int X

{

get

{

返回myValue.X;

}

设置

{

myValue.X = value;

}

}


public int Y

{

get

{

返回myValue.Y;

}

set

{

myValue.Y = value;

}

}


公共Containee getMyValue()

{

返回myValue;

}


public int getX()

{

返回getMyValue()。getX();

}


public int getY()

{

返回getMyValue()。getY();

}

}


公共类Containee

{

public int x;

public int y;


public Containee(int x,int y )

{

X = x;

this.y = y;

}


public int X

{

get

{

return x;

}

套装

{

x =价值;

}

}


public int Y

{

get

{

返回y;

}

设定

{

y = value;

}

}


public int getX()

{

返回x;

}


public int getY()

{

返回y;

}

}

}




I have a story to tell -- with data. I hope that doesn''t scare anyone off.

The question posed by matko has at least two aspects; 1) style and 2)
performance. Style is the first most important aspect when writing
production code. You (and your team) should pick a style and then make sure
that all code follows that style. Having all code written in the same style
will be of unmeasurable value for as long as the code lives.

At some point, performance may become an issue for some parts of the code.
But first impressions are deceiving; especially in this case.

To illustrate this point, I put together a project in MS VisualStudio 2005
(Beta 2 release) that shows the performance difference between 1) direct
access, 2) access through properties, 3) access through getters and 4)
cached values retrieved from getters. I will include the code at the end of
this post. Note that I am running the code on a 2.8GHz HP Pentium 4 Laptop.
The code adds 3 and 5 in a loop that cycles 1000000000 times. The resulting
output when running the code in the IDE using the Debug build is:

[Access using cached values from getters] The sum is: 8000000000 in :
00:00:12.6093750 sec.
[Access using getters] The sum is: 8000000000 in : 00:00:53.2031250 sec.
[Access using properties] The sum is: 8000000000 in : 00:00:38.1093750 sec.
[Direct Access] The sum is: 8000000000 in : 00:00:07.3750000 sec.

[Direct Access] The sum is: 8000000000 in : 00:00:07.3281250 sec.
[Access using properties] The sum is: 8000000000 in : 00:00:37.8437500 sec.
[Access using getters] The sum is: 8000000000 in : 00:00:53.1562500 sec.
[Access using cached values from getters] The sum is: 8000000000 in :
00:00:12.5625000 sec.

Note that I ran the code twice, once in the given order and then another
time in the reverse order as a sanity check. This output shows that direct
access is almost twice as fast as the best of the other approaches. How
much impact does running the debug code in the IDE have? The resulting
output was obtained by running the Debug build from a command prompt:

[Access using cached values from getters] The sum is: 8000000000 in :
00:00:12.5937500 sec.
[Access using getters] The sum is: 8000000000 in : 00:00:45.5937500 sec.
[Access using properties] The sum is: 8000000000 in : 00:00:36.9843750 sec.
[Direct Access] The sum is: 8000000000 in : 00:00:07.2968750 sec.

[Direct Access] The sum is: 8000000000 in : 00:00:07.2968750 sec.
[Access using properties] The sum is: 8000000000 in : 00:00:37.1093750 sec.
[Access using getters] The sum is: 8000000000 in : 00:00:46.1406250 sec.
[Access using cached values from getters] The sum is: 8000000000 in :
00:00:12.5781250 sec.

We might expect that the results should get a little better because there is
no IDE overhead. It is interesting that the worst performer improved the
most. This output shows that direct access is still the clear performance
winner, however. Now examine the output when running the Release build from
a command prompt:

[Access using cached values from getters] The sum is: 8000000000 in :
00:00:10.7031250 sec.
[Access using getters] The sum is: 8000000000 in : 00:00:09.7031250 sec.
[Access using properties] The sum is: 8000000000 in : 00:00:10.6406250 sec.
[Direct Access] The sum is: 8000000000 in : 00:00:10.7031250 sec.

[Direct Access] The sum is: 8000000000 in : 00:00:10.7031250 sec.
[Access using properties] The sum is: 8000000000 in : 00:00:10.5937500 sec.
[Access using getters] The sum is: 8000000000 in : 00:00:09.6875000 sec.
[Access using cached values from getters] The sum is: 8000000000 in :
00:00:10.7031250 sec.

Wow -- they are all nearly equivalent and the worst "debug" performer has a
slight edge over the other approaches. See what I mean. When it comes to
judging performance of code, first impressions can be deceiving. For
production code, there is essentially no performance tradeoff for choosing
one style of accessing over another for case analogous to the example code I
ran. Don''t believe anyone who tells you that there is a performance impact.

Pick the coding style that is best for you and your team and then follow it.
And worry about performance once you have an application that consistently
follows that style where you have measured and identified the real
performance bottlenecks.

Regards,

Randy

Example code follows:
================================================== ====
using System;

namespace CachedVariableProfile
{
public class Program
{
static void Main(string[] args)
{
testWithCachedGetterValues();
testWithAccessUsingGetters();
testWithAccessUsingProperties();
testWithDirectAccess();

testWithDirectAccess();
testWithAccessUsingProperties();
testWithAccessUsingGetters();
testWithCachedGetterValues();
}

public static void testWithAccessUsingProperties()
{
Container dataSupplier = new Container(3, 5);
long sum = 0;

DateTime endTime;
DateTime startTime = DateTime.Now;

for (int i = 0; i < 1000000000; i++)
{
sum += dataSupplier.MyValue.X;
sum += dataSupplier.MyValue.Y;
}

endTime = DateTime.Now;

System.Console.Out.WriteLine("[Access using properties] The sum
is: " + sum.ToString() + " in : " + (endTime - startTime) + " sec.");
}

public static void testWithAccessUsingGetters()
{
Container dataSupplier = new Container(3, 5);
long sum = 0;

DateTime endTime;
DateTime startTime = DateTime.Now;

for (int i = 0; i < 1000000000; i++)
{
sum += dataSupplier.getX();
sum += dataSupplier.getY();
}

endTime = DateTime.Now;

System.Console.Out.WriteLine("[Access using getters] The sum is:
" + sum.ToString() + " in : " + (endTime - startTime) + " sec.");
}

public static void testWithCachedGetterValues()
{
Container dataSupplier = new Container(3, 5);
long sum = 0;

DateTime endTime;
DateTime startTime = DateTime.Now;
int x = dataSupplier.getX();
int y = dataSupplier.getY();

for (int i = 0; i < 1000000000; i++)
{
sum += x;
sum += y;
}

endTime = DateTime.Now;

System.Console.Out.WriteLine("[Access using cached values from
getters] The sum is: " + sum.ToString() + " in : " + (endTime - startTime) +
" sec.");
}

public static void testWithDirectAccess()
{
Container dataSupplier = new Container(3, 5);
long sum = 0;

DateTime endTime;
DateTime startTime = DateTime.Now;

for (int i = 0; i < 1000000000; i++)
{
sum += dataSupplier.myValue.x;
sum += dataSupplier.myValue.y;
}

endTime = DateTime.Now;

System.Console.Out.WriteLine("[Direct Access] The sum is: " +
sum.ToString() + " in : " + (endTime - startTime) + " sec.");
}
}

public class Container
{
public Containee myValue;

public Container(int x, int y)
{
myValue = new Containee(x, y);
}

public Containee MyValue
{
get
{
return myValue;
}
}

public int X
{
get
{
return myValue.X;
}
set
{
myValue.X = value;
}
}

public int Y
{
get
{
return myValue.Y;
}
set
{
myValue.Y = value;
}
}

public Containee getMyValue()
{
return myValue;
}

public int getX()
{
return getMyValue().getX();
}

public int getY()
{
return getMyValue().getY();
}
}

public class Containee
{
public int x;
public int y;

public Containee(int x, int y)
{
X = x;
this.y = y;
}

public int X
{
get
{
return x;
}
set
{
x = value;
}
}

public int Y
{
get
{
return y;
}
set
{
y = value;
}
}

public int getX()
{
return x;
}

public int getY()
{
return y;
}
}
}



这篇关于为什么要创建对象的本地版本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆