首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >DirectCast的性能和后期/早期绑定有什么影响?

DirectCast的性能和后期/早期绑定有什么影响?
EN

Stack Overflow用户
提问于 2015-04-20 13:51:14
回答 2查看 788关注 0票数 10

我一直认为DirectCast()是相当便宜的,在内存方面,并且认为它基本上是帮助我使用IntelliSense的一种方式,例如在事件处理程序中:

代码语言:javascript
复制
Public Sub myObject_EventHandler(sender As Object, e As System.EventArgs)
    'Explicit casting with DirectCast
    Dim myObject As myClass = DirectCast(sender, myClass)

    myObject.MyProperty = "myValue"
End Sub

显然,我认为这对作为开发人员的我更好,但对编译的代码和由此产生的性能也更好,因为它启用了“早期绑定”,而不是.

代码语言:javascript
复制
Public Sub myObject_EventHandler(sender As Object, e As System.EventArgs)
    'No casting at all (late binding)
    myObject.MyProperty = "myValue"
End Sub

..。它也编译和运行,但使用“后期绑定”,如果我得到了正确的术语。即假设sender实际上是一个myClass对象。

关于性能、延迟/早期绑定或任何其他方面,上面的第一个片段与下面的片段有什么不同:

代码语言:javascript
复制
Public Sub myObject_EventHandler(sender As Object, e As System.EventArgs)
    'Implicit casting via variable declaration
    Dim myObject As myClass = sender

    myObject.MyProperty = "myValue"
End Sub

显式DirectCast()调用是有用/有害的,还是在编译器优化代码之后没有什么区别?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-04-20 21:15:24

TL;DR版本:使用DirectCast()代替后期绑定或反射,以获得更好的运行时性能。

这个问题让我很感兴趣。对于我编写的几乎每个应用程序,我都经常使用DirectCast()。我一直使用它,因为它使IntelliSense工作,如果我不使用Option Strict On,那么在编译时就会出现错误。每隔一段时间,我就会使用Option Strict Off,如果我很匆忙,并且我正在测试一个设计概念,或者我在匆忙地寻找一个一次性问题的快速而肮脏的解决方案。我从来没有考虑过在使用它时的性能效果,因为我从来没有考虑过运行时性能与我编写的东西有关。

考虑到这个问题,我有点好奇,所以我决定试一试,自己看看不同之处。我在Visual中创建了一个新的控制台应用程序并开始工作。下面是应用程序的全部源代码。如果您想亲自查看结果,您应该能够直接复制/粘贴:

代码语言:javascript
复制
Option Strict Off
Option Explicit On
Imports System.Diagnostics
Imports System.Reflection
Imports System.IO
Imports System.Text


Module Module1
    Const loopCntr As Int32 = 1000000
    Const iterationCntr As Int32 = 5
    Const resultPath As String = "C:\StackOverflow\DirectCastResults.txt"

    Sub Main()
        Dim objDirectCast As New MyObject("objDirectCast")
        Dim objImplicitCasting As New MyObject("objImplicitCasting")
        Dim objLateBound As New MyObject("objLateBound")
        Dim objReflection As New MyObject("objReflection")
        Dim objInvokeMember As New MyObject("objInvokeMember")
        Dim sbElapsed As New StringBuilder : sbElapsed.Append("Running ").Append(iterationCntr).Append(" iterations for ").Append(loopCntr).AppendLine(" loops.")
        Dim sbAverage As New StringBuilder : sbAverage.AppendLine()

        AddHandler objDirectCast.ValueSet, AddressOf SetObjectDirectCast
        AddHandler objImplicitCasting.ValueSet, AddressOf SetObjectImplictCasting
        AddHandler objLateBound.ValueSet, AddressOf SetObjectLateBound
        AddHandler objReflection.ValueSet, AddressOf SetObjectReflection
        AddHandler objInvokeMember.ValueSet, AddressOf SetObjectInvokeMember

        For Each myObj As MyObject In {objDirectCast, objImplicitCasting, objLateBound, objReflection, objInvokeMember}
            Dim resultlist As New List(Of TimeSpan)
            sbElapsed.AppendLine().Append("Time (seconds) elapsed for ").Append(myObj.Name).Append(" is: ")
            For i = 1 To iterationCntr
                Dim stpWatch As New Stopwatch
                stpWatch.Start()
                For _i = 0 To loopCntr
                    myObj.SetValue(_i)
                Next
                stpWatch.Stop()
                sbElapsed.Append(stpWatch.Elapsed.TotalSeconds.ToString()).Append(", ")
                resultlist.Add(stpWatch.Elapsed)
                Console.WriteLine(myObj.Name & " is done.")
            Next

            Dim totalTicks As Long = 0L
            resultlist.ForEach(Sub(x As TimeSpan) totalTicks += x.Ticks)
            Dim averageTimeSpan As New TimeSpan(totalTicks / CLng(resultlist.Count))
            sbAverage.Append("Average elapsed time for ").Append(myObj.Name).Append(" is: ").AppendLine(averageTimeSpan.ToString)
        Next

        Using strWriter As New StreamWriter(File.Open(resultPath, FileMode.Create, FileAccess.Write))
            strWriter.WriteLine(sbElapsed.ToString)
            strWriter.WriteLine(sbAverage.ToString)
        End Using
    End Sub

    Sub SetObjectDirectCast(sender As Object, newValue As Int32)
        Dim myObj As MyObject = DirectCast(sender, MyObject)
        myObj.MyProperty = newValue
    End Sub

    Sub SetObjectImplictCasting(sender As Object, newValue As Int32)
        Dim myObj As MyObject = sender
        myObj.MyProperty = newValue
    End Sub

    Sub SetObjectLateBound(sender As Object, newValue As Int32)
        sender.MyProperty = newValue
    End Sub

    Sub SetObjectReflection(sender As Object, newValue As Int32)
        Dim pi As PropertyInfo = sender.GetType().GetProperty("MyProperty", BindingFlags.Public + BindingFlags.Instance)
        pi.SetValue(sender, newValue, Nothing)
    End Sub

    Sub SetObjectInvokeMember(sender As Object, newValue As Int32)
        sender.GetType().InvokeMember("MyProperty", BindingFlags.Instance + BindingFlags.Public + BindingFlags.SetProperty, Type.DefaultBinder, sender, {newValue})
    End Sub
End Module

Public Class MyObject
    Private _MyProperty As Int32 = 0
    Public Event ValueSet(sender As Object, newValue As Int32)
    Public Property Name As String

    Public Property MyProperty As Int32
        Get
            Return _MyProperty
        End Get
        Set(value As Int32)
            _MyProperty = value
        End Set
    End Property

    Public Sub New(objName As String)
        Me.Name = objName
    End Sub

    Public Sub SetValue(newvalue As Int32)
        RaiseEvent ValueSet(Me, newvalue)
    End Sub

End Class

我尝试在没有附加Visual调试器的情况下运行Release配置中的应用程序以及运行发布配置。以下是输出的结果:

使用Visual调试器发布:

代码语言:javascript
复制
Running 5 iterations for 1000000 loops.

Time (seconds) elapsed for objDirectCast is: 0.0214367, 0.0155618, 0.015561, 0.015544, 0.015542, 
Time (seconds) elapsed for objImplicitCasting is: 0.014661, 0.0148947, 0.015051, 0.0149164, 0.0152732, 
Time (seconds) elapsed for objLateBound is: 4.2572548, 4.2073932, 4.3517058, 4.480232, 4.4216707, 
Time (seconds) elapsed for objReflection is: 0.3900658, 0.3833916, 0.3938861, 0.3875427, 0.4558457, 
Time (seconds) elapsed for objInvokeMember is: 1.523336, 1.1675438, 1.1519875, 1.1698862, 1.2878384, 

Average elapsed time for objDirectCast is: 00:00:00.0167291
Average elapsed time for objImplicitCasting is: 00:00:00.0149593
Average elapsed time for objLateBound is: 00:00:04.3436513
Average elapsed time for objReflection is: 00:00:00.4021464
Average elapsed time for objInvokeMember is: 00:00:01.2601184

没有Visual调试器的发布:

代码语言:javascript
复制
Running 5 iterations for 1000000 loops.

Time (seconds) elapsed for objDirectCast is: 0.0073776, 0.0055385, 0.0058196, 0.0059637, 0.0057557, 
Time (seconds) elapsed for objImplicitCasting is: 0.0060359, 0.0056653, 0.0065522, 0.0063639, 0.0057324, 
Time (seconds) elapsed for objLateBound is: 4.4858827, 4.1643164, 4.2380467, 4.1217441, 4.1270739, 
Time (seconds) elapsed for objReflection is: 0.3828591, 0.3790779, 0.3849563, 0.3852133, 0.3847144, 
Time (seconds) elapsed for objInvokeMember is: 1.0869766, 1.0808392, 1.0881596, 1.1139259, 1.0811786, 

Average elapsed time for objDirectCast is: 00:00:00.0060910
Average elapsed time for objImplicitCasting is: 00:00:00.0060699
Average elapsed time for objLateBound is: 00:00:04.2274128
Average elapsed time for objReflection is: 00:00:00.3833642
Average elapsed time for objInvokeMember is: 00:00:01.0902160

从这些结果来看,与在转换中添加编译器相比,使用DirectCast()几乎没有影响性能。然而,当依赖于对象延迟绑定时,会对性能造成巨大影响,并且执行速度会大大减慢。在使用System.Reflection时,直接转换对象的速度略有减慢。我认为获得PropertyInfo比使用.InvokeMember()方法要快得多,这是不寻常的。

结论:尽可能使用DirectCast()或直接转换对象。应该只在需要时才使用反射。只使用后期装订的项目作为最后的手段。事实上,如果您只是在这里或那里修改一个对象几次,那么它可能不会在总体方案中起作用。

相反,您应该更加关注这些方法如何失败,以及如何阻止它们这样做。例如,在SetObjectInvokeMember()方法中,如果sender对象没有MyProperty属性,那么这段代码就会引发异常。在SetObjectReflection()方法中,返回的属性信息可能是nothing,这将导致NullReferenceException

票数 8
EN

Stack Overflow用户

发布于 2015-04-20 15:00:19

我建议在for循环中运行大约100,000次的后期绑定和直接强制转换,看看两者之间是否存在时间差。

为两个循环创建停止表,并打印出结果。如果有什么不同,请告诉我们。100,000次可能太低了,实际上你可能会让它运行得更长。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29749832

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档