装配中的脑袋

用程序装配大脑,再用大脑装配程序
随笔 - 118, 评论 - 1214, 引用 - 11

导航

关于

如果想发较大的信件,请用Ninputer @ gmail.com

不要在我的Blog评论中张贴广告,除非同意向我付款。

标签

每月存档

最新留言

广告

试用“停表”高精度计时

.NET Framework 2.0中增加了一项新的诊断工具——“停表”StopWatch类,相比以前的计时系统,停表采用的是高精度计时方式,因此对性能测量更有帮助。为了试用StopWatch类,我选择了一个经典的测试题目,VB中的IIf函数。IIf函数与C系列的?:三元运算符十分相似,可以在一行语句内完成判断和赋值两项任务。但是,IIf是函数而不是运算符,其接受Object类型参数这一项已经够让人担忧的了。IIf到底有多慢呢?我们比较三个版本。首先是VB类库中的Object版:

Public Function IIf(Expression As Boolean, _
    TruePart As Object, FalsePart As Object)As Object

第二个版本,是我编写的泛型版本的IIf,这个版本可以用于减少装箱拆箱过程带来的性能损失:

Public Function IIf(Of T)(Expression As Boolean, _
    TruePart As T, FalsePart As T)As T
    If Expression Then
        Return TruePart
    Else
        Return FalsePart
    End If
End Function

第三个版本当然是直接使用If语句。我们已经很清楚哪个比较快,但是没有一个量的概念,通过高精度计时的测试,可以让我看到函数内联化带来的收益是否够多。下面是计时和测试的代码:

Dim watch As New System.Diagnostics.Stopwatch

Dim j As Integer = 0
Dim f As Boolean = True

'Loop 10 times and get the average time
For times As Integer = 1 To 10

    watch.Start()
    For i As Integer = 0 To 1000000
        j = Interaction.IIf(f, i, 5)
    Next
    watch.Stop()

Next

GC.Collect()

TextBox1.AppendText("Object IIf: " & watch.ElapsedMilliseconds / 10 & vbCrLf)

watch.Reset()
For times As Integer = 1 To 10

    watch.Start()
    For i As Integer = 0 To 1000000
        j = IIf(f, i, 5)
    Next
    watch.Stop()

Next

GC.Collect()

TextBox1.AppendText("Generic IIf: " & watch.ElapsedMilliseconds / 10 & vbCrLf)

watch.Reset()
For times As Integer = 1 To 10

    watch.Start()
    For i As Integer = 0 To 1000000
        If f Then j = i Else j = 5
    Next
    watch.Stop()

Next

TextBox1.AppendText("Pure If: " & watch.ElapsedMilliseconds / 10 & vbCrLf)

我们看到StopWatch可以像真的停表一样开始,停止或继续,因此我们可以像在科学实验中计时一样使用它。而他的Elapsed属性可以提供各种单位的时间间隔。简单起见,我就用了毫秒。循环的次数不太多,取10次平均。最后的结果在我的机器上如下:

Object IIf: 219.6
Generic IIf: 51.5
Pure If: 9.7

纯If仅9.7毫秒的间隔也能测试出来,足见StopWatch的精度比原来的计时手段高多了。而结果也表明,函数调用的代价已经相当可观,但还不如装箱、拆箱带来的代价高。IIf当然是不要再用了,今后自己写函数时也应当注意,频繁调用的函数不能不考虑调用代价,内联化是不错的解决方案。

posted on 2004-07-31 13:29:00 by Ninputer  评论(20) 阅读(6600)

Visual Basic 2005新功能点评(十六)——My命名空间之My.Resources和My.User

从原理上来说,My.Resources与前面介绍的My.ComputerMy.Application是完全不同的,他带来的是另一种方便。My.Resource不是一个类库,而是My命名空间中唯一一个子命名空间。他的功能是什么呢?我们先回忆一下在.NET Framework1.1时代使用资源的情形。首先我们得通过工具,将图片、文本或声音等资源添加到资源列表中,编译成资源文件,再嵌入到我们的程序集中。当我们要使用资源的时候,必须通过System.Resources.ResourceManager从程序集中提取资源,然后自行判断资源的类型,做适当的转化并使用。比如从Form1的资源中取出ID为Greeting的字符串,需要写这么多代码:

Dim manager As New System.Resources.ResourceManage( _
    "MyApp.Form1", Me.GetType().Assembly)
Dim s As String = manager.GetString("Greeting")

而且那个编辑resx的界面不太直观,只添加字符串资源就不太方便,要想添加图片、音乐等文件到资源文件并在程序中取用就更麻烦了。到现在,许多Visual Basic .NET程序员还总是询问将图片音乐嵌入到EXE文件中去的方法。.NET Framework 2.0为解决这个问题引入了一个新特性——强类型资源。首先ResourceManager增加了一个GetStream()方法,方便获取图片、声音类的资源,其次Resgen工具可以根据资源的内容生成一个包装类,通过它可以直接强类型地读些程序集内的资源。而Visual Basic 2005将强类型资源与VB的IDE的特性结合在一起,就成了方便无比的My.Resources。

在实际使用My.Resources之前,我们先看看Visual Basic 2005新的资源编辑器,它现在已经继承到了项目属性中。打开项目属性并切换到Resources选项卡,我们可以看到如下的资源编辑器。

从顶端的下拉列表框中,可以选择资源的类型——声音、图像、文本、文件、图标或其他自定义内容。选择相应的类别,下面的编辑器就会发生变化,以适应当前类型的资源。每种类别都可以添加任意数量的资源。比如我们添加一个名称为Greeting的字符串,并让它的值等于"Hello",然后切换到代码窗口,输入My.Resource.看到什么了?Greeting弹出来了。现在我们使用这个资源之需要一行代码了。对比刚才所述的旧方法,你感到方便之处了吗?

Dim s As String = My.Resources.Greeting

如果我们添加了图片资源,那么也可以直接使用My.Resources来访问,而且就是BitMap类型,你想怎样用它就可以怎样用它,比如:

BackgroundImage = My.Resources.MyPic

一行代码就可以轻轻松松将窗口背景设置为资源中的图片。如果储存了声音资源,那么结合My.Computer.Audio的功能,播放资源中的声音也变得如此简单:

My.Computer.Audio.PlaySound(My.Resources.MySound)

想象一下以前要多少代码才能完成这样一个任务!有了My.Resource,资源的使用变得非常简单,你一定会改变对使用资源的看法,而爱上在自己的程序中使用资源的。

My.User是My命名空间中最小的成员,但是别看他小,功能对于.NET新手来说却不简单。如果你初次接触.NET开发,要获取当前登陆用户的用户名和用户组怎么办呢?谁会想到它其实是和Thread.CurrentPrincipal属性有关呢?My.User简单地将用户名和角色信息提供给你,要想获得当前登录的用户名,只需要输入My.User.Identity就行了。

下期预告

My命名空间的最后两个功能——My.Forms和My.WebServices

posted on 2004-07-29 13:39:00 by Ninputer  评论(8) 阅读(4390)

Visual Basic 2005新功能点评(十五)——My命名空间之My.Computer

My.Computer可能是My命名空间中最有趣的部分了,这一部分封装了大量访问系统和硬件信息的功能,操作起来比直接使用.NET Framework或Windows API都方便得多。My.Computer中有很多对象,下面我们分别来介绍。

My.Computer.Audio

Audio对象提供了播放音频的功能,它既可以从wav等文件播放,也可以从音频数据流来播放,就是说你可以用它轻松播放储存在资源文件中或者数据库中的音频。播放时还可以指定后台播放或等待结束等多种设置。结合My.Resources来使用,更显得方便无穷。这是一个简单的播放wav文件的例子:

My.Computer.Audio.Play("c:\ding.wav", AudioPlayMode.BackgroundLoop)

My.Computer.Clipboard

Clipboard对象提供了以强类型方式读写剪贴板的功能,比Windows.Forms里面的剪贴板更加好用。使用Clipboard对象可以直接从剪贴板读写音频、图像、文本甚至我的电脑中的文件拖放信息。此外,由VB6升级的项目现在将直接使用My.Computer.Clipboard对象升级以前的Clipboard对象,这将解决VB.NET不能升级原先剪贴板功能的缺陷。下面的例子将文本框内的内容复制到剪贴板:

My.Computer.Clipboard.SetText(TextBox1.Text)

My.Computer.Clock

Clock对象是一个获取时间的工具,它可以直接获取当地时间、中时区的时间和从当时子时开始的毫秒计数。

My.Computer.FileSystem

这是微软Visual Basic Team在My.Computer中倾注最多精力的对象,使用它可以充分改善文件操作的复杂程度。FileSystem对象提供了易于理解的操作方式。FileSystem对象中复制文件的方法不但只需要指定目标路径,还可以帮助你建立目标目录中不存在的级别。它还特别提供了CopyDirectory的功能,可以复制整个目录!这正是目前.NET Framework缺乏的功能。同时FileSystem还能提供搜索上级目、子目录或根目录的功能,非常体贴。下面例子展示了如何在动画演示下将文件放入回收站。

My.Computer.FileSystem.DeleteFile("c:\mybigfile.big", True, True)

FileSystem对象还提供了只用一行代码就可以读取文本文件内容,或者将所需内容写入文本文件的功能,现在你不需要再用迷惑人的StreamReader、StreamWriter来读写文件了,还不用担心资源释放的问题。如下面的例子:

s = My.Computer.FileSystem.ReadAllText("c:\a.txt")

除了可以通过My访问以外,通过System.IO.FileSystem类也可以完成FileSystem对象的大多数功能,这种方式似乎更适合于使用C#或C++的开发者。

My.Computer.Info

看名字就知道了,这个对象的属性都是系统信息。如果你想获得本机物理内存或虚拟内存的总数,剩余量、操作系统名称、当前用户名、本机安装的文化设置等等,都可以轻松使用Info对象,它让你对应用程序所在的系统了如指掌。

My.Computer.Keyboard和My.Computer.Mouse

通过这两个对象,你可以快速获得用户键盘的信息,如大写锁定、数字键盘锁定等是否打开,以及鼠标有几个按键,是否配备滚轮等。如果你希望你的应用程序能够做到最体贴用户,那这些信息是少不了了。下面例子演示获取用户的鼠标左右键功能是否交换(这样你就可以知道用户是不是左撇子,从而提供更体贴的界面,多爽)

Dim f As Boolean = My.Computer.Mouse.ButtonsSwapped

My.Computer.Name

不用多说,这就是本机操作系统安装时输入的名称

My.Computer.Network

这个Network对象充分简化了最常用的网络任务,只需要一行代码,就可以Ping一个地址,或者检测网络是否接通。还能用一行代码下载或上传文件。比如这个例子就完成了一个下载文件的任务:

If My.Computer.Network.IsAvailable Then
    My.Computer.Network.DownloadFile("
http://abc.com/x.zip", _
        "C:\download")
End If

My.Computer.Port

提供了用一行代码打开本机串口的功能,还能立刻绑定一个事件监视串口的变化。现在串口编程出奇的简单,再也不需要MSComm控件了。

My.Computer.Printers

这个Printers对象能够遍历本机所安装的所有打印机,还能找出默认的打印机。通过向默认打印机画图一样的操作,就能开始打印了。这样的操作会让你想起VB6时代便利而简洁的打印操作。下面的例子将在默认打印机上打印一个椭圆。从VB6升级项目时,原来的Printer对象将自动升级为My.Computer.Printers中的相关操作,升级的用户可以更加放心了。

My.Computer.Printers.DefaultPrinter.DrawEllipse( _
    New RectangleF(2, 2, 50, 150), 1)
My.Computer.Printers.DefaultPrinter.Print()

My.Computer.Registry

这个注册表对象可比Microsoft.Win32空间中的那个版本简单多了,他提供强类型的路径支持,还能非常方便地读写注册表。下面的例子是一段内置的代码片断,演示了如何判断某一键值是否存在。

Dim exists As Boolean = True

Dim path As String = "Software\Microsoft\TestApp\1.0"

If My.Computer.Registry.CurrentUser.OpenSubKey(path) Is Nothing Then
    exists = False
End If

My.Computer.Screen

Screen对象可以获取屏幕的可视范围,像素的位数等。比VB6的Screen对象更强的是,它现在支持两个显示器。

现在我们已经了解了My.Computer中的所有对象,这些对象将大部分任务简化成一行代码,对你的日常编程是不是非常有帮助呢?

下期预告

下期我们介绍Visual Basic中的强类型资源——My.Resources

posted on 2004-07-28 09:27:00 by Ninputer  评论(22) 阅读(7904)

Visual Basic的自举和语言的执拗

通过长时间分析Microsoft.VisualBasic.dll我发现了一个重要的问题:首先,Visual Basic语言运行时是要依靠Microsoft.VisualBasic.dll这个运行库的,其中类型转换、字符串比较和异常处理更是直接依靠该运行库中的类型。所以,Visual Basic开发应用程序无法不引用这个运行库。但是,大量的迹象表明,Microsoft.VisualBasic.dll是用Visual Basic开发的,不但Visual Basic的总设计师承认了这一点,运行库中的很多代码也体现了这一点,比如大量运用可选参数,以及使用了C#无法生成的try filter特性。那么是怎么用Visual Basic开发运行库自身的呢?它总不能引用还没有开发出来的自己吧?

另外一件事,我发现C#不允许将普通函数声明为类型的名字,比如Form1中不允许出现

public void Form1()

这样的声明。为什么呢?怕和构造函数弄混吗?但是构造函数没有返回类型,这是不可能弄混的啊。我用Visual Basic生成了与类型名一样的函数,然后拿到C#中调用,发现他能够很好地处理这种情况。那为什么不允许自己声明成这样呢?Visual Basic就没有这样的问题,虽然Visual Basic将New指定为构造函数的名字,但是却可以声明叫做New但不是构造函数的函数,只要这样写就行了。

Public Sub [New]()

语言设计者的想法,有时候很难捉摸。

posted on 2004-07-24 22:35:00 by Ninputer  评论(10) 阅读(2186)

继承的Singleton

在讨论My名字空间的时候,IceShark让我看了一个他写的类库,这是一个封装了大量Windows常见操作的类,和My的思想颇有异曲同工之妙。其中一个命名空间让我倍感兴趣:DesignPatterns.CreationalPatterns。竟然能将设计模式做成类库,这是我前所未见的。我特地看了一下他的Singleton类,只有一个Instance()静态方法,当然是为了获取唯一的实例用的。但Singleton类没有其他任何功能,我们要使用显然要继承它。但问题是,继承一个Singleton类还是Singleton吗?我们看看Instance()的实现方法(在此对作者表示歉意,原库是没有源代码的,我进行了一点反向工程):

public static Singleton Instance()
{
    if(__Singleton == null)
        __Singleton = new Singleton();
    return __Singleton;
}

清楚地看到,new是作用在Singleton上的,只能返回Singleton的实例,而不能返回他子类的实例。此外,子类的变量也不能引用父类的实例,所以继承这个Singleton类根本不能做成能用的Singleton。那我们究竟有没有办法实现继承后的类仍是Singleton呢,我觉得可以尝试一下泛型:

Public Class Singleton(Of T As {Singleton(Of T), New})
    Private Shared _instance As T
    Private Shared _syncRoot As New Object

    Public Shared Function GetInstnce() As T
        If _instance Is Nothing Then

            SyncLock _syncRoot
                If _instance Is Nothing Then
                    _instance = New T
                End If

            End SyncLock
        End If

        Return _instance
    End Function
End Class

 现在我们可以试试继承这个类了:

Public Class SingSub
    Inherits Singleton(Of SingSub)

End Class

注意,我们这里为什么要约束基类自身,主要是保证T的取值范围,否则就会做成工厂类了。这里的SingSub类的确像是一个Singleton了,可以作用这种语法使用它:

Dim s As SingSub = SingSub.GetInstnce()

但是,又一个问题出现了,这里约束了New,就必须让子类有一个可公共访问的构造函数,这可与Singleton大相径庭。私有他的构造函数又不能采用这个约束。不知大家对这种情况有没有什么好的解决方法,或者说Singleton模式还是无法写成类库的。

posted on 2004-07-20 12:58:00 by Ninputer  评论(13) 阅读(3367)

Visual Basic 2005新功能点评(十四)——My命名空间之My.Application

关键字:VB8.0 VB.NET VB2005 My namespace

Visual Basic不同于Visual C#、Visual C++之处在于它更偏重于快速开发,更针对非专业开发人员和编程新手。Visual Basic 2005这次提供的“My”是一个极为出色的设计,可以帮助开发人员快速利用.NET Framework中的各种功能进行开发。说到My到底是什么,其实它就是一个工程相关的命名空间,其中的内容是由IDE帮助你组织的。

在My出现以前,.NET Framework已经具有强大而丰富的类库,学习这些类库算不上是一件轻松的事。许多VB或VC的开发者第一次接触到.NET开发时,总是习惯于自己实现或通过调用Windows API实现某些.NET早已准备好的功能。其原因就是.NET类库太庞大太分散了,许多常用的功能与那些不太常用的功能混在一起。比如,获得从当日零点开始的毫秒数的方法(经常被用来做随机数的种子)竟然与设置环境变量功能同在Environment类中,而不是“看上去像是”的System.Timers、TimeSpan或DateTime等命名空间或类型中。许多开发者对类库不熟悉,于是就一遍又一遍地重复开发.NET Framework的功能。Visual Basic Team为了解决这个问题,设计了My命名空间,它将.NET Framework中最常用的功能挑出来,然后按照最容易理解的逻辑结构存放在一起。当你深入My命名空间,你会发现那些功能就在你凭直觉就能想象到的路径中。

My命名空间在当前版本中主要包含My.Application、My.Computer、My.Resources、My.User、My.Forms和My.Webservices等六个主要部分。你可以输入My关键字找到他们,也可以导入My命名空间,其语法是:

Imports 项目名称.My

在My命名空间中的所有类或对象中,My.Application是与当前运行的应用程序有关的对象,本次首先来介绍My.Application。My.Application提供的功能非常丰富,比如当前应用程序的主线程、主窗口、版本或公司版权等信息、文化和语言设置、路径及命令行、事件日志甚至Splash Screen的信息。下面的表格列出了My.Application的全部功能。

My.Application 成员 描述
ApplicationContext 应用程序的上下文,包括主线程和主窗体的信息
AssemblyInfo 程序集信息,包括版本、版权、标题、产品名称和可执行名称等
ChangeCurrentCulture 改变应用程序当前文化设置,如货币和时间的格式
ChangeCurrentUICulture 改变应用程序当前的用户界面文化设置,如显示语言和用词
CommandLineArgs 一个只读集合,返回当前应用程序的命令行参数。这些参数已经分隔开,无须像原来那样手工分隔Command函数的值了。
CurrentCulture 返回当前的文化设置
CurrentDirectory 返回应用程序使用的当前目录
CurrentUICulture 返回当前的用户界面文化设置
Deployment 返回按照ClickOnce方法部署的应用程序的Deployment对象
DoEvents 执行储存在Windows消息队列中的所有Windows消息
Exit 退出应用程序
GetEnvironmentVariable 通过环境变量的名字获取环境变量的值
IsNetworkDeployed 返回一个值,指示当前应用程序是否采用了网络部署方式
Log 一个记录应用程序事件日志和异常的日志工具
MainForm 当前应用程序的主窗体
OpenForms 当前应用程序中所有已经打开窗体的集合,与VB6的Forms集合功能相同
Run 启动Visual Basic的启动/关闭应用程序模式
SplashScreen 返回当前应用程序作为Splash Screen的窗口

可以注意到,My.Application中的某些功能和Application对象是一样的,但是My.Application不仅仅能用于Windows Form的应用程序,许多功能在控制台应用程序照样能够使用。下面举几个简单的例子来使用My.Application:

1、显示一个简单的关于窗口。

With My.Application.AssemblyInfo
    Dim msg As New System.Text.StringBuilder
    msg.AppendLine("Protuct Name: " & .ProductName)
    msg.AppendLine("Company Name: " & .CompanyName)
    msg.AppendLine("Version: " & .Version.ToString)
    msg.AppendLine("Description: " & .Description)

    MsgBox(msg.ToString, MsgBoxStyle.Information, "About " & .Title)
End With

2、将当前打开的所有窗口的标题都改为环境变量%TITLE%的值

For Each f As Form In My.Application.OpenForms
    f.Text = My.Application.GetEnvironmentVariable("TITLE")
    DoEvents() '也可以写成My.Application.DoEvents()
Next

3、检查如果从网络上部署,修改当前用户界面文化设置为英语-美国

If My.Application.IsNetworkDeployed Then
    My.Application.ChangeCurrentUICulture("en-US")
End If

还有很多很多不同的用法,大家可以亲自试试。有了My.Application,设置和获取应用程序信息变得非常容易和有趣。这才是使用Visual Basic真正的感觉。

下期预告

和计算机硬件系统有关的My.Computer

posted on 2004-07-18 13:49:00 by Ninputer  评论(15) 阅读(7121)

为自己的属性编写一个编辑器

网上经常有这样的问题:在设计控件时,怎样让自己的属性在属性窗口中显示的时候加一个“…”按钮或者下拉列表框,然后通过自定义的编辑器来编辑该属性的值。我举一个常见的例子,假设你的属性是表示一个路径,你希望在属性窗口中显示时可以有一个“…”按钮,单击之后显示一个目录选取对话框,可以通过它直接选取文件夹。

首先,要编写一个Editor类,继承自System.Drawing.Design.UITypeEditor:

Imports System.Security.Permissions
Imports System.ComponentModel
Imports System.Drawing.Design
Imports System.Windows.Forms

Public Class PathEditor
    Inherits UITypeEditor

    <PermissionSet(SecurityAction.Demand, Name:="FullTrust")> _
    Public Overrides Function EditValue(ByVal context As ITypeDescriptorContext, _
        ByVal provider As IServiceProvider, ByVal value As Object) As Object

        Using chooseDialog As New FolderBrowserDialog()
            With chooseDialog

                .ShowNewFolderButton = False
                .Description = "Choose the folder of " & _
                    context.PropertyDescriptor.DisplayName
                .SelectedPath = CStr(value)
                .RootFolder = Environment.SpecialFolder.MyComputer
                .ShowDialog()
                Return .SelectedPath
            End With
        End Using

    End Function

    <PermissionSet(SecurityAction.Demand, Name:="FullTrust")> _
    Public Overrides Function GetEditStyle( _
        ByVal context As ITypeDescriptorContext) As UITypeEditorEditStyle

        Return UITypeEditorEditStyle.Modal

    End Function

    <PermissionSet(SecurityAction.Demand, Name:="FullTrust")> _
    Public Overrides Function GetPaintValueSupported( _
        ByVal context As ITypeDescriptorContext) As Boolean

        Return False

    End Function

End Class

  在实现这个类时,应当重写UITypeEditor的几个方法。GetEditStyle方法返回一个数,指示编辑器采用外部的编辑器(显示“…”,并弹出窗口)还是使用下拉式列表。本例我们使用外部编辑器。如果不重写这个方法,默认是不会有任何特殊编辑方式的。GetPaintValueSupported方法返回是否支持对属性编辑器重画。我们经常看到颜色属性的编辑器可以直接显示颜色,图标属性的编辑器可以显示图标的缩略图等,都是通过这个功能完成。在这里我们不需要它。最后EditValue属性就是对编辑方式的具体定义。我们需要一个目录选择对话框来编辑目录,就可以在代码中建立它。value参数表示编辑此属性之前属性的值,contex参数则能提供一些有关属性本身的信息。

编写完毕以后,我们就可以给我们的属性绑定这个编辑器。用的是EditorAttribute,例子如下:

<Editor(GetType(PathEditor), GetType(UITypeEditor))> _
Public Property PerlPath() As String
    Get
        Return
_PerlPath
    End Get
    Set
(ByVal value As String)
        _PerlPath = value
    End Set
End Property

这个EditorAttribute要接受两个参数,一个是Editor类的类型,就是刚才我们编写的那个类,一个必须是UITypeEditor本身的类型,用GetType运算符可以获得。现在,你的属性已经可以用自定义的编辑器编辑了。如图:

单击那个编辑按钮以后,弹出编辑器:

还有很多种编辑器,如对集合属性编辑的编辑器,对自定义结构编辑的编辑器等,都可以自由设计,然后通过编写Editor即可用于设计你自己的属性。

posted on 2004-07-16 18:11:00 by Ninputer  评论(12) 阅读(4456)

Visual Basic的静态导入

由于Visual Studio 2005意外挂掉,所以Visual Basic 2005新功能点评也只好推后。最近看了JDK1.5要给JAVA增加的新功能包括“静态导入”。功能就是将类型的静态成员导入,以便简化代码的书写。比如在JAVA中使用别人定义的常数一直是一个问题,JAVA中,常数都必须做成静态只读字段,因此使用常数都必须采用“类型名.常数名”的语法。由于JAVA允许在接口中定义静态字段,所以许多人将常数定义在接口中,再实现这个接口以避免输入类型名的麻烦,但这样不符合接口本来的功能,属于不良的设计。为此JAVA增加了静态导入,允许导入类型的静态成员,这样就不必写类型名了。

VB一直就没有这个问题,因为VB有模块,在模块里定义常数直接用名字就可以使用,无需类型名。因此许多人没发现VB有静态导入的功能。但是除了常数,我们有时候也想导入一些特定类的静态方法。最典型的就是Math类。在VB.NET刚推出的时候,许多人问Sin和Cos这些函数上哪里去了,其实就在那里,只不过必须写成Math.Sin,Math.Cos,这多麻烦呀。你可以用静态导入解决这个问题:

Imports System.Math

把这么简单的一句话放在文件开头,后面再用Sin、Cos之类的函数就不需要写Math了,直接用,就和内置函数一样方便。除了Math以外,我还常常静态导入System.Console,Application等,这样WriteLine或者DoEvents这样的常用方法就可以直接用了。

不过C#的开发人员不认为静态导入是一个值得加入的特征,所以C#至今没有静态导入。

posted on 2004-07-10 19:31:00 by Ninputer  评论(9) 阅读(1684)

有趣的新Console

.NET Framework 2.0 BETA的Console类加了很多新的属性和方法,现在可以改变背景颜色,字符颜色等等,还能移动控制台的缓冲区。如

Imports System.Console
Imports System.Threading

Module Module1

    Sub Main()
        BackgroundColor = ConsoleColor.Green
        ForegroundColor = ConsoleColor.Magenta
        Clear()
        WriteLine("Hello World")

        For i As Integer = 1 To 20

            MoveBufferArea(i - 1, i - 1, 1, 1, i, i)
            Thread.Sleep(100)

        Next

        Read()
    End Sub

End Module

效果如图:

posted on 2004-07-09 13:10:00 by Ninputer  评论(6) 阅读(1791)

Visual Basic 2005新功能点评(十三)——XML文档注释

安装了Visual Basic 2005 Express Edition Beta以后,我立刻被My的功能和新的项目属性窗口吸引了,泛型的智能感知也基本完善了。所以我后面将开始着重介绍这些最受人瞩目的功能。但是今天我还是按照计划,来介绍这个XML文档注释。

书写文档是程序员讨厌的任务之一,因为文档与代码的同步以前完全要靠手工进行。C#和Java引入的“注释文档”很大程度上简化了这个问题。它的基本原理就是将书写到代码中的特定注释提取出来,就可以生成代码的文档。现在,VB2005的XML文档注释给你的便利不仅仅如此,用了它你一定会爱上写文档。

Visual Basic 2005的文档注释是基于XML语法的,它可以描述代码中每一个类型和每一个成员的信息。在Visual Basic中只要输入'''(连续输入3个单引号)就可以输入XML格式的文档注释。比如

''' <summary>
''' 说明部分
'''
</summary>
Public Class Form1

XML文档注释描述的是紧接注释部分的代码元素,一旦开始就不能断开,也不能掺杂其他代码元素,直到所有的XML标记被关闭。<summary>是VB推荐使用的标记,是该描述元素的摘要。除了<summary>,常用的标记有<remark>,表示说明;<param>表示参数信息;<exception>表示异常,此外还有<include>和<permission>等等。不一定非要使用这些推荐的标记,但是这些标记使用时可以自动完成,而且能被IDE所利用,如图所示:

XML文档注释写好以后,就可以用vbc.exe或者Visual Basic的IDE提取这些注释,生成所需的文档。你可以在项目属性对话框方便地找到生成文档的功能。下面就是生成文档的一部分,描述的是一个叫SubName的方法:

<member name="M:WindowsApplication1.Form1.SubName">
 <summary>
 This is the summary of this member.
 </summary>
 <remarks></remarks>
</member>

大写的M表示成员,而后面则是该成员的名称。有了这个XML文档,加上特定XSLT,就能生成一篇漂亮的报告。VB的编译器可以自动探测还没有编写文档的成员,还能检验特定成员的文档编写是否全面无误。

除了生成文档之外,书写XML文档注释最大的好处就是可以获得智能感知的支持。在VB5/6等早期版本,可以通过成员属性对话框为成员编写帮助,现在你只要写注释就行了。比如上面那个例子,当文档注释书写完毕后,再使用SubName的时候就会自动显示提示:

XML格式的文档提取出出来后将放到与程序集相同的文件夹中,这样其他项目甚至其他语言使用这些程序集时,也可以获得智能感知的提示。

XML文档注释的第二个好处是用来生成精美的报文。从“工具”菜单中选择“生成代码注释文档”就可以了,这样生成的报文能够快速察看所写代码的所有成员及说明。

XML文档注释是许多VB程序员盼望的功能,有许多第三方插件实现此功能,不过当然是官方的好用啦。下期介绍My命名空间。

posted on 2004-07-07 13:09:00 by Ninputer  评论(7) 阅读(4860)

Visual Basic中的接口显式实现 & VB代码着色器

最近在博客园看到了多篇讨论C#“接口显式实现”的贴子,显式实现主要有两个功能:处理接口成员重名和隐藏实现接口的成员,还有一些与CLR内部原理有关的功能。如果VB程序员需要处理接口成员重名或者想隐藏实现接口的成员,可能也想要C#的接口显式实现功能,但是VB不提供显式实现的功能,换之以自由方式处理。

VB实现接口用的是Implements语句指定所实现的接口成员,因此实现方法本身的名字和访问级别是任意的。假如Interface1和Interface2都有一个叫Test的成员,而开发者需要将实现Interface1.Test的方法设为Public,而实现Interface2的方法隐藏(Private),就可以这么写:

Public Sub Test() Implements Interface1.Test
End Sub

Private Sub
Test2() Implements Interface2.Test
End Sub

这种做法在C#里已经无法实现了。而VB甚至可以让实现接口成员的方法为Protected或者Friend访问级别,还可以任意添加Overridable使它成为虚方法。所有这些都是自由的,不像C#接口显式实现那样受到约束。关于这条特征的原理,请参见《VB.NET是怎样做到的》

此外,博客园最近改良了代码着色工具,使它能够折叠代码。这让我太羡慕了,不知道是不是只支持C#。目前VB.NET代码着色功能都不太完善,很多地方上色不对,而且不支持将标识符、字符串、运算符等分别着色,控制力不强。因此我想开发一个VB.NET的代码着色工具,基于微软的Visual Basic .NET Parser。但是我对折叠代码这方面不太熟,希望得到熟悉这方面的大虾的帮助。

posted on 2004-07-03 23:05:00 by Ninputer  评论(4) 阅读(2295)

关于VB运算符重载的一篇MSDN文章

这篇文章介绍了运算符重载的语法、用途,还介绍了许多运算符重载的使用规则和技巧。如果对运算符重载有兴趣,可以参考这篇文章:

Operator Overloading in Visual Basic 2005

posted on 2004-07-03 12:15:00 by Ninputer  评论(1) 阅读(2672)

Visual Basic 2005新功能点评(十二)——无符号整型

关键字:VB2005 VB8.0 VB.NET Whidbey unsigned types

BASIC语言的类型系统在其发展过程中是不断完善的。实用派的Microsoft BASIC系列首先给Visual Basic增加了整型类型,VB又增加了Date型和Currency型;;VB4中加入了Boolean、Object和Byte类型;VB5加入了Decimal类型;VB.NET又加入了Char类型和更大的整型。VB.NET的类型系统依靠.NET Framework类型已经非常完善。但是在Visual Basic的发展史上从没有支持过无符号整数,而C系列的语言则对他们有良好的支持。因此Visual Basic在与C/C++编写的代码进行交互时总是会遇到障碍。.NET Framework支持无符号整型,但是他们不符合CLS,Visual Basic .NET也没有支持他们。事实上,无符号整型用处也不是很大,只是在进行平台交互的时候常会用到他们。不管怎么说,Visual Basic 2005现在支持他们,你可以用他们进行计算,就像其他类型一样。

Visual Basic 2005支持的无符号整型和有符号的SByte类型都是对.NET Framework中现有支持的无符号整型结构体的映射。下表列出了这些新类型的取值范围和映射的结构体:

Visual Basic中的名称 字面符号 取值范围 映射的结构
UShort US 0~65535 System.UInt16
UInteger UI 0~4294967295 System.UInt32
ULong UL 0~18446744073709551615 System.UInt64
SByte -128~127 System.SByte

字面符号是用来表示这些类型字面常量的,比如100可以表示有符号整数,也可以表示无符号,但是100UI就只能表示UInteger的100。对无符号整数的运算超出他们的取值范围默认会发生溢出异常,而将无符号整数转换为相应大小的有符号整数时,若所表示的数超过相应的有符号整数所能表示的范围,也会发生溢出异常,使用时应当注意。

Visual Basic 2005还引入了几个新的类型转换运算符,用于其他类型到无符号类型的强制类型转换。他们是CUShort,CUInt,CULng和CSByte。他们的用法与其它类型转换运算符是一样的。如:

Dim ui As UInteger = 100UI
Dim us As UShort = CUShort(ui) '显式转换
Dim ul As ULong = ui '隐式转换

注意无符号整型到同样大小的有符号整型不是扩大转换,而是缩小转换,在Option Strict完全打开的状态下只能进行显式转换。

Visual Basic 2005还支持创建基于无符号整型的枚举类型,只要在枚举定义的时候指定即可。比如指定基于ULong类型的枚举:

Public Enum MyEnum As ULong
    A
    B
    C
End Enum

这时,MyEnum类型就和ULong类型一样,他的变量可以取任何ULong能取的数值。而A、B和C变量也都是实质为ULong类型的常数。

无符号整型最常用在与平台进行交互的地方,比如COM交互或调用平台的API。比如调用Win32的API函数:

Public Class windowsMessage
    Private Declare Auto Function mb Lib "user32.dll" Alias "MessageBox" _
        (ByVal hWnd As Integer, _
        ByVal lpText As String, _
        ByVal lpCaption As String, _
        ByVal uType As UInteger) As Integer

    Private Const MB_OK As UInteger = 0
    Private Const MB_ICONEXCLAMATION As UInteger = &H30
    Private Const IDOK As UInteger = 1
    Private Const IDCLOSE As UInteger = 8
    Private Const c As UInteger = MB_OK Or MB_ICONEXCLAMATION

    Public Function messageThroughWindows() As String
        Dim r As Integer = mb(0, "Click OK if you see this!", _
            "Windows API call", c)
        Dim s As String = "Windows API MessageBox returned " _
            & CStr(r)& vbCrLf & "(IDOK = " & CStr(IDOK) _
            & ", IDCLOSE = " & CStr(IDCLOSE) & ")"
        Return s
    End Function
End Class

下期预告

XML文档注释

posted on 2004-07-01 21:51:00 by Ninputer  评论(6) 阅读(5396)

Powered by: Joycode.MVC引擎 0.5.2.0