vb.net

位置:IT落伍者 >> vb.net >> 浏览文章

VB.NET中的动态代码生成技巧


发布日期:2022年08月10日
 
VB.NET中的动态代码生成技巧

本文的讨论也将着眼于这两种情况首先是当程序员需要动态建立一个控件并将代码附着于控件之上时例如你或许想创建一个链接列表但是不知道需要创建链接的数量或是链接中会出现什么样的数据第二种是当程序员需要定义代码以反映出特殊需求的时候例如你或许要执行能反映用户系统配置的代码

类似上述的情况当然不会每天都上演事实上它们只在非常情况下才出现然而作为程序员仍然要意识到NET为解决动态情形提供了方案有了正确的技巧你就可以写出能灵活处理动态情况的应用程序了

使用动态控件

许多程序员总会遇到需要动态创建控件的时候我们所展示的例子中程序员向FlowLayoutPanel中添加了LinkLabels或许你可以个这样的设置来记录和保存常用的URL文件网络地址或是其他资源所在位置的数值这一示例没有真正保存链接但是你可以使用XML序列化功能来实现保存

每次当用户点击Test按钮时示例代码就会动态创建一个新的LinkLabel控件真正的演示代码并不复杂例一就展示了创建这类控件以及将控件放入FlowLayoutPanellstLabel中通常所需要做的一切

例一向FlowLayoutPanel中添加新的链接

PrivateSubbtnTest_Click()

HandlesbtnTestClick

Createalink

DimNewLinkAsLinkLabel=

NewLinkLabel()

Addsomepropertiestoit

NewLinkText=DateTimeNow

ToLongTimeString()

Settheclickeventhandler

AddHandlerNewLinkClick

AddressOfNewLink_Click

Placethebuttonontheform

lstLinksControlsAdd(NewLink)

EndSub

如你所料该代码开始的时候创建了一个新的LinkLabel并为其赋予了一些值这一示例使用的是当前时间你的代码或许能够对某一真实资源进行访问

请注意该代码也向链接的Click事件中指定了一个处理程序你必须使用示例中的AddHandler技巧因为普通的Handles关键词路径不起作用一方面设计应用程序的时候你并不清楚控件的名称即便你为控件指定了一个名称你也不知道用户要创建的控件数量所以我们没有办法清楚会有多少处理程序会被创建处理程序的代码与控件代码类似因此没有必要创建多个处理程序用于这个示例的处理代码见例二例二处理动态控件点击事件

PrivateSubNewLink_Click(_

ByValsenderAsSystemObjectByValeAsSystemEventArgs)

VerifythatyouactuallyhaveaLinkLabel

IfNotsenderGetType()IsGetType(LinkLabel)Then

MessageBoxShow(Wrongcontroltypeprovided!)

Return

EndIf

ConverttheinputsendertoaButton

DimThisLinkAsLinkLabel=sender

Showthatwehavethecorrectbutton

MessageBoxShow(Youcreatedthislinkat:+ThisLinkText)

EndSub

你可能已经注意到例一中的事件处理器使用的是宽松代表——它没有将ByVal发送器作为SystemObject也没有将ByVal e作为SystemEventArgs作为参数因为它不需要这二者然而当你创建一个事件处理器来动态创建控件时通常你需要将ByVal发送器作为SystemObject参数这意味着将这两者都包含其中

有些程序员在创建事件处理器的时候会出现一个错误即没有检查传入控件的类型发送器对象可能包含多选择而如果未对事件处理器进行事件处理类型的设置那么你就会面临更多的选择我们的示例代码一开始就检查了传入控件对象的类型这样以来发送器就不会像下面所展示的代码一样

PrivateSubbtnTest_Click()HandlesbtnTestClick

Createalink

DimNewButtonAsButton=NewButton()

Addsomepropertiestoit

NewButtonText=DateTimeNowToLongTimeString()

Settheclickeventhandler

AddHandlerNewButtonClickAddressOfNewLink_Click

Placethebuttonontheform

lstLinksControlsAdd(NewButton)

EndSub

此代码在FlowLayoutPanel中创建了一个按钮大多数情况下这都能正常运行除非事件处理器不按照按钮所示的进行操作如果你打算服务多个控件类型那么每个控件类型都需要一个独特的处理你可以使用多事件处理器或者为某些类型提供选择标准

NewLink_Click()事件处理器照常将传入发送器转换成指定类型在这个示例中则是LinkLabel该代码可以访问LinkLabel属性并能用其他方式进行互动在我们的示例中只显示了一个能在创建链接的时候告知我们的对话框

使用动态代码

在运行时创建一个控件是在无法确定应用程序功能的时候采取的一种策略但是动态创建控件并不适用于所有的情况有些时候你必须建立可执行代码虽然你的应用程序运行的目的是补偿不同极其之间的配置不同用户的需求不同的环境需求或是其他要求当应用程序所运行的电脑不存在控件那么通常是需要创建动态代码的

幸运的是NET为我们提供了一系列动态代码选项例如你可以创建一个可执行的能独立运行的程序或是可以想运行中的程序加载一个DLL然后再执行当你需要演示一个外部任务的时候可以使用选择可执行如运行一种脚本——该DLL选项最适合扩大现有的应用程序功能

你可以运行来自文件或内存的动态代码当你需要不止一次地运行代码时可以使用文件对代码的检查可以再次运行外部文件而不需要对其进行二次编译当你需要多次演示任务的时候如一个安装请求那可以使用内存图像

当然我们也可以更改源代码例如你可以使用字符串来建立需要在应用程序中直接使用的代码如果你需要代码具有高度灵活性且代码本身不是很长时这一方法的优势就非常显着也可以从文件里建立代码就如同VS一样这一方法最适用于相对稳定且不需要复杂编码的需求第三种选择是使用Documentation Object Model来创建代码并将其作为CodeDom树型结构的一个系列该树型结构包括了CodeCormpileUnits这就像是用DOM模式创建了一个XML文件

使用动态创建代码的最好方式是用示例来检查一下例三展示了一个基本Hello World示例该示例用源代码直接创建了代码因此你可以看到整个运行以及生成一个外部可执行文件的过程

例三动态编码示例

PrivateSubbtnTest_Click()HandlesbtnTestClick

Createacompiler

DimCompAsVBCodeProvider=NewVBCodeProvider()

Definetheparametersforthecodeyouwanttocompile

DimParmsAsCompilerParameters=NewCompilerParameters)

WedowanttocreateanexecutableratherthanaDLL

ParmsGenerateExecutable=True

ThecompilerwillcreateanoutputassemblycalledOutput

ParmsOutputAssembly=Output

Thecompilerwonttreatwarningsaserrors

ParmsTreatWarningsAsErrors=False

Addanyassemblyyouwanttoreference

ParmsReferencedAssembliesAdd(SystemWindowsFormsdll)

Definethecodeyouwanttorun

DimSampleCodeAsStringBuilder=NewStringBuilder()

SampleCodeAppend(ImportsSystemWindowsForms+vbCrLf)

SampleCodeAppend(ModuleTestAssembly+vbCrLf)

SampleCodeAppend(SubMain()+vbCrLf)

SampleCodeAppend(MessageBoxShow(+Chr()+_

DynamicallyCreatedCode!+_Chr()+)+vbCrLf)

SampleCodeAppend(EndSub+vbCrLf)

SampleCodeAppend(EndModule+vbCrLf)

Definethecodetorun

DimExecutableAsCompilerResults=_

CompCompileAssemblyFromSource(ParmsSampleCodeToString())

Displayerrormessagesifthereareany

IfExecutableErrorsHasErrorsThen

ForEachItemAsCompilerErrorInExecutableErrors

MessageBoxShow(ItemErrorText)

Next

Else

Iftherearentanyerrormessagesstartthe

executable

ProcessStart(Output)

EndIf

EndSub

一开始你创建了一个使用VBCodeProvider的编译器Comp旧一点的NET版本使用的是不同的方法但是这里所讲的是微软推荐的一个新方法

为了使用编译器你必须创建能描述应用程序的参数这些参数类似于VS中你创建的参数只是现在你可以对它们进行定义该代码一开始就将GenerateExecutable设置为True这意味着你需要的是一个EXE文件而不是DLL

ParmsOutputAssembly属性包含了输出文件的名称你只需要在想创建文件时提供这一信息即可而不需要生成可执行内存了如果你ixiang生成可执行文件的内存版本可以将ParmGenerateInMemory属性设置为True

使用ParmTreatWarningsAsErrors属性来确定如何处理警告信息默认的设置会使其为错误这意味着你的应用程序可能无法对其进行编译大多数程序员使用默认设置尽管他们开发了程序但是在开发完成的程序中却将其设置为False

大多数应用程序需要外部DLL以正常运行当然你不能创建任意的没有引用外部DLL的Windows表单程序通常你要使用Reference文件夹来完成这一任务不过当你动态创建代码的时候可以依赖于ParmsReferencedAssemblies属性如下所示只需添加你要的DLL即可

现在你已经定义了项目接下来需要为其创建源代码如前文所述你可以依赖于一个外部文件或DOM模式然后该示例创建了代码因此你可以看到整个过程下面是代码的原始形式

ImportsSystemWindowsForms

ModuleTestAssembly

SubMain()

MessageBoxShow(DynamicallyCreatedCode!)

EndSub

EndModule

这个简单的例子显示了一个对话框注意vbCrLf的使用如果你不使用这一方法那编译器会发送给你一个错误信息vbCrLf条目在该代码中所起的作用与在程序代码中的作用相同只是添加的方式不一样

从这一点老说你最后会用CompCompileAsseblyFromSource()方法编译代码当使用DOM模式和文件的时候可以使用这一方法而在所有三种情况中编译器用参数和源代码创建了你请求的输出该运算的输出出现在Executable中是CompilerResults类型

编译的失败次数多于程序员的预计无论你是在哪里使用动态编码技巧你必须假设会出现失败的情况以及处理失败的方案在本例中代码寻找的是错误并在编译失败时将其展示在了信息框中否则代码会依赖于ProcessStart()方法来启用可执行文件

底线

动态编码技巧并不是万能钥匙当你为开发问题找到了好的静态解决方案时当然也可以使用但是在我们所列出的情况中没有可行的静态方案因此要选择动态编码技巧大多数情况下要用动态编码技巧解决以下问题

◆ 用户的环境会以不可预见的方式更改时

◆ 无法控制用户电脑的安装

◆ 用户或应用程序都添加了你要用控件执行的数据要素

◆ 应用程序必须执行很早以前的安装任务且这些任务与电脑环境网络或其他不确定因素联系紧密时

◆ 应用程序要执行了处理级别的任务且这些任务取决于机器连接或其他状况

显然还有其他一些情况能使用动态编码技巧最重要的是记住但凡有不可预知的情况下要考虑使用动态编码技巧通常在编码环境中出现了静态代码无法处理的情况时我们就可以使用动态编码技巧

上一篇:vb.net入门之分组控件:GroupBox控件

下一篇:VB.NET入门--Imports 语句