VB.NET是怎样做到的(五、六)

VB.net 是怎样做到的(五)——实现接口

VB.net 采用的实现接口的语法是 VB5 发明的 Implements ,这个实现接口的语法在当今主流语言中独一无二。比如我有两个接口:

Interface ** Interface1 ** **
** Sub Test()
End Interface

Interface ** Interface2 ** **
** Sub Test()
End Interface

这两个接口有一个完全一样的成员 Test 。假设我需要用一个类同时实现两个接口会怎么样呢?先想想看,如果是 Java , JScrip.NET 这样的语言就只能用一个 Test 函数实现两个接口的 Test 成员。假如两个 Test 只是偶然重名,其内容必须要分别实现怎么办,于是一些解决接口重名的设计出现了……。在 VB 中,独特的 Implements 语句可以让你想怎么实现接口就怎么实现,比如下面的类 Implementation 用两个名字根本不一样的方法实现了两个接口。

Public Class ** Implementation ** **
** Implements ** Interface1 ** , ** Interface2 **

Public Sub Hello() Implements ** Interface1 ** .Test

End Sub

Private Sub Hi () Implements ** Interface2 ** .Test

End Sub
End Class

也就是说, VB 允许用任意名字的函数实现接口中的成员,而且访问器可以是任意的,比如想用 Public 还是 Private 都可以。

C# 在处理重名成员上提供了显式实现( explicit implementation )的语法,其实现上述两个接口的语法为

public class ** Class1 ** : ** Interface1 ** , ** Interface2 **
{
public Class1()
{
}
void ** Interface1 ** .Test()
{
}

void ** Interface2 ** .Test()
{
}

}

注意这里, C# 只能用接口名 . 成员名的名字来命名实现方法,而且访问器只能是 private ,不能公开显式实现的方法。

在考察了 IL 以后,我发现 .NET 支持隐式实现和显式实现两种方式。其中隐式实现只要在类里面放一个与接口成员方法名字一样的方法即可——这一种 VB 不支持。而显式实现则在方法的描述信息里加入:

.override TestApp.Interface1::Test

无论是 C# 的显式实现还是 VB 的 Implements 语句都是这样的原理。也就是说 .NET 提供了换名实现接口成员的功能,但是只有 VB 将这个自由让给了用户,而其他语言还是采用了经典的语法。

VB.NET 是怎样做到的(六)——默认属性和属性参数

在原先的 VB6 里,有一项奇特的功能——默认属性。在 VB6 中,对象的名称可以直接表示该对象的默认属性。比如 TextBox 的默认属性是 Text ,所以下面的代码

Text1.Text = "Hello"

就可以简化为

Text1 = "Hello"

这种简化给 VB 带来了很多麻烦,赋值运算就需要两个关键字—— Let 和 Set ,结果属性过程也需要 Let 和 Set 两种。而且这种特征在后期绑定的时候仍能工作。到了 VB.NET ,这项功能被大大限制了,现在只有带参数的属性才可以作为默认属性。如

List1.Item(0) = "Hello"

可以简化为

List1(0) = "Hello"

这种语法让有默认属性的对象看起来像是一个数组。那么 VB 怎么判断一个属性是否是默认属性呢?看下列代码

Public Class PropTest

Public Property P1( ByVal index As Integer ) As String

Get

End Get

Set ( ByVal Value As String )

End Set

End Property

Default Public Property P2( ByVal index As Integer ) As String

Get

End Get

Set ( ByVal Value As String )

End Set

End Property

End Class

P1 和 P2 两个属性基本上完全相同,唯一的不同是 P2 带有一个 Default 修饰符。反汇编这个类以后,可以发现两个属性完全相同,没有任何差异。但是 PropTest 类却被增加了一个自定义元属性 System.Reflection.DefaultMemberAttribute 。这个元属性指定的成员是 InvokeMember 所使用默认类型,也就是说后期绑定也可以使用默认属性。可是我试验将 DefaultMember 元属性手工添加到类型上却不能达到让某属性成为默认属性的功能。看来这项功能又是 VB 的一项“语法甜头”。但是, VB 或 C# 的编译器对别人生成的类的默认属性应该只能通过 DefaultMemberAttribute 来判断,所以我将一个 VB 类只用 DefaultMemberAttribute 指定一个默认方法,不使用 Default ,然后将它编译以后给 C# 用,果然, C# 将它识别为一个索引器( indexer )!

既然说到了 C# 的索引器,我们就顺便来研究一下 VB 和 C# 属性方面的不同。刚才的实验结果是 VB 的默认属性在 C# 中就是索引器。但是 VB 仍然可以用属性的语法来访问默认属性,而 C# 只能用数组的语法访问索引器。更特别的是, VB 可以创建不是默认属性,但是带有参数的属性,如上面例子里的 P1 ,而 C# 则不支持带参数的属性,如果将 VB 编写的,含有带参数属性的类给 C# 用, C# 会提示“属性不受该语言支持,请用 get_XXX 和 set_XXX 的语法访问”。也就是说,带参数的属性是 CLR 的一项功能,但不符合 CLS (通用语言规范),因此就会出现跨语言的障碍。这也更加深了我们对 CLS 的认识——如果你希望让你的代码跨语言工作,请一定要注意符合 CLS 。

Published At
Categories with Web编程
Tagged with
comments powered by Disqus