我正在更新一些旧代码,并且已经找到了几个实例,每次需要调用其中一个属性或方法时,都会重复转换相同的对象。例如:
if (recDate != null && recDate > ((System.Windows.Forms.DateTimePicker)ctrl).MinDate)
{
((System.Windows.Forms.DateTimePicker)ctrl).CustomFormat = "MM/dd/yyyy";
((System.Windows.Forms.DateTimePicker)ctrl).Value = recDate;
}
else
{
(System.Windows.Forms.DateTimePicker)ctrl).CustomFormat = " ";
}
((System.Windows.Forms.DateTimePicker)ctrl).Format = DateTimePickerFormat.Custom;
我倾向于修复这种怪异,但考虑到我有限的时间,我不想打扰任何不影响功能或性能的东西。
所以我想知道的是,这些冗余的演员是否被编译器优化了?我试着通过在一个简化的例子中使用ildasm来解决这个问题,但不熟悉IL我只是更加困惑。
更新
到目前为止,共识似乎是a)不,演员表没有优化,但b)虽然可能会有一些小的性能影响,但它不太可能显着,并且c)我应该考虑无论如何要修理它们。如果我有时间的话,我有一天会解决这些问题。同时,我不会担心它们。
谢谢大家!
答案 0 :(得分:21)
对Release版本中生成的机器代码进行抽查,表明x86抖动不会优化抛弃。
你必须看看这里的大图。您正在分配控件的属性。它们有很多副作用。对于DateTimePicker,分配会导致将消息发送到本机Windows控件。而这反过来又扼杀了这条消息。铸件的成本可以忽略不计副作用的成本。重写作业永远不会在速度方面产生明显的差异,你只能使它快一点点。
继续,在一个懒惰的星期五下午重写代码。但这只是因为它对可读性有害。可读性差的C#代码也会产生效率低下的机器代码并不完全是巧合。
答案 1 :(得分:18)
在调试或发布版本中,它没有与IL进行优化。
简单的C#测试:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace RedundantCastTest
{
class Program
{
static object get()
{ return "asdf"; }
static void Main(string[] args)
{
object obj = get();
if ((string)obj == "asdf")
Console.WriteLine("Equal: {0}, len: {1}", obj, ((string)obj).Length);
}
}
}
对应的IL(注意多个castclass
指令):
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 3
.locals init (
[0] object obj,
[1] bool CS$4$0000)
L_0000: nop
L_0001: call object RedundantCastTest.Program::get()
L_0006: stloc.0
L_0007: ldloc.0
L_0008: castclass string
L_000d: ldstr "asdf"
L_0012: call bool [mscorlib]System.String::op_Equality(string, string)
L_0017: ldc.i4.0
L_0018: ceq
L_001a: stloc.1
L_001b: ldloc.1
L_001c: brtrue.s L_003a
L_001e: ldstr "Equal: {0}, len: {1}"
L_0023: ldloc.0
L_0024: ldloc.0
L_0025: castclass string
L_002a: callvirt instance int32 [mscorlib]System.String::get_Length()
L_002f: box int32
L_0034: call void [mscorlib]System.Console::WriteLine(string, object, object)
L_0039: nop
L_003a: ret
}
它也没有从发布版本中的IL优化:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 3
.locals init (
[0] object obj)
L_0000: call object RedundantCastTest.Program::get()
L_0005: stloc.0
L_0006: ldloc.0
L_0007: castclass string
L_000c: ldstr "asdf"
L_0011: call bool [mscorlib]System.String::op_Equality(string, string)
L_0016: brfalse.s L_0033
L_0018: ldstr "Equal: {0}, len: {1}"
L_001d: ldloc.0
L_001e: ldloc.0
L_001f: castclass string
L_0024: callvirt instance int32 [mscorlib]System.String::get_Length()
L_0029: box int32
L_002e: call void [mscorlib]System.Console::WriteLine(string, object, object)
L_0033: ret
}
这两种情况都不意味着在生成本机代码时不会优化转换 - 您需要查看实际的机器组件。即通过运行ngen和拆卸。如果它没有被优化,我会非常惊讶。
无论如何,我会引用The Pragmatic Programmer和破碎的窗口定理:当你看到一个破窗口时,修复它。
答案 2 :(得分:6)
没有; FxCop将此标记为性能警告。请参阅此处的信息:http://msdn.microsoft.com/en-us/library/ms182271.aspx
如果您想找到要修复的内容,我建议您在代码上运行。
答案 3 :(得分:1)
我从未听说过或看到过CLR上的冗余演员优化。让我们尝试一个人为的例子
object number = 5;
int iterations = 10000000;
int[] storage = new int[iterations];
var sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++) {
storage[i] = ((int)number) + 1;
storage[i] = ((int)number) + 2;
storage[i] = ((int)number) + 3;
}
Console.WriteLine(sw.ElapsedTicks);
storage = new int[iterations];
sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++) {
var j = (int)number;
storage[i] = j + 1;
storage[i] = j + 2;
storage[i] = j + 3;
}
Console.WriteLine(sw.ElapsedTicks);
Console.ReadLine();
在我的机器上,在发布下运行,我可以获得大约350k的冗余冗余和280k的自动优化。所以不,看起来CLR没有针对此进行优化。