首页 > 开发 > 综合 > 正文

代码换肤术(一)——C#和VB

2024-07-21 02:20:10
字体:
来源:转载
供稿:网友

代码换肤术(一)——c#和vb
现在流行程序“换肤术”,就是把操作界面变个样子,程序当然还是原来的程序。代码的移植也可以称为一种“换肤术”,内容不改,但变成了另一种语言。本文介绍的是从当今最火热的c#与vb.net间移植的技巧。

按理说,这两种语言没有什么移植的必要,因为他们生成的代码可以完全通用。但是如果一个工程基本上是vb写成的,却需要少许已经存在的c#过程,用组件并不是一种效率很高的办法。就算是学习c#或vb,学会他们之间的移植可以双倍的利用已经存在的代码(如好玩的donkey.net就只有vb版)。

有人比较过这两种语言,得出的结论是他们很相似。但即便是这样,vb初学者看到诸如((button)sender).text = “启动”;之类的语法不知道如何移植到vb,而c#初学者看到handles button1.click等语法也会为移植而感到头痛。下面就看看他们最难移植的部分:

1、option语句。vb的option语句可以打开或关闭变量声明检查和类型转换检查。尤其是option strict被关闭后,vb变成弱类型语言,很多类型转换都是自动的,移植到c#中会产生无数错误。因此,如果要将带有option strict off语句的vb程序移植到c#,最好先在vb中将option strict打开,然后把所有类型转换出错的地方变成强类型转换,然后再进行移植。

2、类型转换。vb提供了很多类型转换函数型运算符,如cint(), csng(), cstr()等,在c#中只要用(int) , (float), (string)即可。然而如果不是标准类型,如下面的c#语句:

((system.button)sender).text = “启动”;

就要使用vb的函数型运算符ctype来实现。上面的代码正确的移植方法是:

ctype(sender, system.button).text = “启动”

千万不要使用某些人推荐的,将option strict关闭,然后用后期绑定调用sender对象的方法,这根本不符合程序移植不能改变本质的要求。

3、修饰符和属性标签。vb和c#的修饰符是完全对等存在的,但是拼写往往不同,给移植带来了很多麻烦,尤其是表示相同意思的关键字从字面理解完全不同的时候。下面就给出了vb和c#对应的关键字:

vb
c#
vb
c#

inherits
:
implements
:

mustinherit
abstract
notinheritable
sealed

overridable
virtual
notoverridable
sealed

mustoverride
abstract
overrides
override

[overloads]

shadows
new

shared
static
public
public

protected
protected
friend
internal

protected friend
protected internal
private
private

static
用别的方法实现
byval


byref
ref
optional


paramarray
params
无法实现
unsafe

无法实现
fixed


可以看出,vb的关键字比较长,而且使用上也比c#更加严格。从c#向vb移植的时候,要分外注意哪些vb有而c#没有的关键字以及在c#拼写相同,在vb中拼写不同的关键字(如mustoverride和mustinherit)。有些关键字如unsafe,如果c#使用了他们,将无法移植到vb中。好在这些关键字在商业应用中并不常用。

属性标签在这两种语言中非常的相似,移植上应该没有任何难度,只要知道在c#中用方括号[]表示属性标签,而在vb中用的是尖括号<>。另外,如果要用名称结合传递参数,c#直接使用=号,而vb使用:=(冒号和等号)。

4、委派类型。委派类型就是安全的函数指针类型。在c#中,难以分辨是函数指针在工作还是函数本身在工作,因为他们的语法相同。当要为一个委派类型的变量复制的时候,直接等于一个函数即可,如:

public delegate void functype(object e)

...

functype func;

func = new functype(this.samplefunction1);

//调用

func(something);

//换指向另外一个函数

func = this.samplefunction2

然而vb中,委派类型就像是一般的对象,有它的方法,与函数本身明显不同。你不能将过程的名字直接赋给一个委派类型的对象,而必须使用addressof运算符,下面的例子就是上文c#程序的vb版,注意那些实现不同的地方:

public delegate sub functype(byval e as object)

...

dim func as functype

func = new functype(addressof me.samplefunc1)

‘ 调用

func.invoke(something)

‘ 换指向另外一个函数

func = addressof me.samplefunction2

5、事件处理。这是两种语言最大的差别之一,vb传承以前版本强大的事件处理机制,许多语法都比c#更加灵活。好在无论什么情况,他们之间都是可以互相移植的。

对于事件定义,两种语言都是一个委派类型加一个事件属性,如:

[c#]

public delegate void myeventhandler(object sender, eventargs e);

public event myeventhandler myevent;

[visual basic]

public delegate sub myeventhandler(byval sender as object, byval e as eventargs)

public event myevent as myeventhandler

vb还支持另外一种更加紧凑的定义方法,只有一条语句:

public event myevent(byval sender as object, byval e as eventargs)

移植的时候,要把参数部分分离出来,成为一个委派类型,再按照普通方法定义事件即可。

关于事件响应,c#与delphi等语言一样,是动态绑定事件过程的,其语法类似于下:

internal myclass myobj;

...

myobj = new myclass();

...

myobj.myevent += this.myobj_myevent;

...

protected void myobj_myevent(object sender, eventargs e)

{

//语句

}

可以看到,c#是利用运算符连接事件过程和事件属性的。之后,还可以用-=运算符解除事件过程与事件属性的绑定。vb不支持运算符重载,但仍然支持这种动态绑定的事件过程,方法是使用addhandler和removehandler关键字。如上面黑体部分可以移植为:

addhandler myobj.myevent, addressof me.myobj_myevent

解除绑定的语法与此类似,只是关键字为removehandler而已。一定不要忘记过程前面还有一个addressof关键字!

动态绑定的事件过程工作起来比较慢,vb支持一种更快的静态绑定事件过程。一旦为对象设置了静态的事件过程,就不能解除绑定,一般大多数情况都是如此。语法如下:

‘ 定义变量时使用withevents关键字

friend withevents myobj as myclass

‘ 直接书写事件过程,注意handles的语法:

protected sub myobj_myevent(byval sender as object, byval e as eventargs) _

handles myobj.myevent

‘ 语句

end sub

它表示myobj_myevent这个过程仅仅响应myobj.myevent这个过程。如果一个过程要响应很多个事件,把他们列在handles后面,用逗号隔开,如handles event1, event2, ...

遇到这种情况,要看清handles后面的所有对象和事件,将它们一一改写成动态绑定的语句:

protected sub xxx(...) handles myobj1.myevent, myobj2.myevent

==>

myobj1.myevent += this.xxx;

myobj2.myevent += this.xxx;

...

protected void xxx(...){}

当事件比较多时,c#显著变得比较麻烦,幸好一个过程响应一大堆事件的情况也不太多(不过我就编写过一个过程相应8个事件,移植起来好麻烦!)。原则上说,将静态事件过程移植为动态事件过程并没有完全遵守移植的规定,但我估计他们实现的原理不会相差太多,所以也不用担心。

6、异常处理。vb支持两种形式的异常,即.net框架的异常和vb自己的错误号码。而c#只支持第一种。用到vb自己的错误号码的程序几乎无法移植到c#中,所以应该尽量使用.net框架的异常,如下面vb语句:

try

‘ 发生错误的代码

catch when err.number = 52

‘ 解决错误的代码

end try

这段代码无法直接移植到c#中,只有用exception对象取代err对象获得异常信息,才能顺利移植。另外vb的when语句带给try语句十分灵活的用法,必须用很高的技巧才能在c#中实现,这就需要具体问题具体分析了。

vb支持exit try语句,可以直接从try块或catch块跳转到finally块。c#没有提供类似的语法,可以用以下技巧:

[visual basic]

try

‘ 一些语句

exit try

finally

‘ 一些语句

end try

[c#]

try

{

//一些语句

goto __leave;

}

finally

{

//一些语句

}

__leave: //别忘了这里还有哦!

总之是利用了finally块无法跳过的特征,用goto语句模拟了exit try语句。

如果vb程序用的是vb特有的on error goto语句实现的错误处理,问题就麻烦了。代码可能在过程中上下跳跃,无法预料语句的执行方式。这种代码理解起来就头痛,更不要说移植了。总体来说,把所有语句统统转移到try块中,然后用catch一一处理错误。遇到要返回(resume语句)的时候,只好copy代码了。反正不是一件容易的事情,慢慢改就是了。

7、模块。vb支持模块,c#不支持。但也没有关系,只要在c#中制造一个abstract类,共享所有成员,就和模块一样了。当然不能像vb一样直接访问模块中的成员,需要用到“类名.成员名”的用法。

8、接口。c#在接口方面也没有vb强大(怎么这么重要的功能也不做得好一点?),vb采用implements语句结合接口的成员和类的实现成员,而c#是用名称结合。因此vb就可以随便修改实现成员的访问级别和名称,而c#就不能改名称。将c#移植为vb时,最好利用vb.net编辑器直接实现接口,比较简单。把vb移植为c#时,就必须把改过的名字都改回来,遇到名字冲突就更讨厌了(这时候我几乎不想再移植为c#了)。给一个例子:

[visual basic]

public class class1 : implements imyinterface

public sub dosth() implements imyinterface.method1

end sub

end class

[c#]

public class class1 : imyinterface

{

public void method1()

{

}

}

9、运算符重载。这会遇到vb头痛了,既然vb不支持运算符重载,那么就必须用子程序和函数来模拟运算符。比如建立plus和minus方法模拟+和-的运算。当然还是有很多情况(比如遇上了explicit和implicit语句)就真的没有办法了,只好不移植了。运算符重载是一个很不错的功能,它能使很多操作简单地完成,如果vb支持它,就真的是完美语言了。

好了,想必最麻烦的地方已经说完了,剩下的就是简单的copy了。虽然有些地方还没有说清楚,但基本上阐明了两种语言的不同(一看,不同还挺多的吧),反正也不用移植大的工程,了解这些内容主要是为了利用双倍的利用已经存在的代码,但愿本文对你有用。由于水平低劣,如有错误请各位大虾指正,小弟必洗耳恭听。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表