如何在 VB6 中使用包含列表的 .NET 类
创建 VB6 可以使用的 .NET 类包装器很容易,但类型之间存在一些困难,特别是泛型列表。
引言
注意:页面上并非包含所有代码,构造函数和项目下载中提供的其他指令缺失。
本文将在您希望使用在 .NET 中“设计”的类,并通过 Visual Basic .NET 中的“COM 类”在 VB6 中使用的特殊情况下为您提供帮助。
背景
仍有大量公司试图从 VB6 迁移到 .NET。这可能就像运行集成的 VS 转换工具一样简单,或者如果公司有资源和时间,他们会决定重写。
如果这个重写是基于一种新的架构,使用了大多数新应用程序将使用的 N 层和通用 DLL,那很酷... 但是,一旦您完成了其中一个 .NET DLL,您就必须将这个新库集成到您的 VB6 应用程序中,该怎么办?
使用 VB.NET 中的“COM 类”并创建一个调用您组件的业务逻辑层,创建一个 *.tlb 文件并在您的 VB6 项目中引用它,这并不难。然而,有些类型在 VB6 中不可用;例如 .NET 的 Long
在 VB6 中不存在,而 .NET 的 Integer
实际上是 VB6 中的 Long
。更不用说 VB6 中根本没有列表(称为泛型),您可以使用数组,但它们在 .NET 中的工作方式与 VB6 不同。
Using the Code
让我们从一个简单的问题开始。
您有以下类
您需要获得一个经销商列表,每个经销商将包含描述和汽车列表,每辆汽车包含制造商、型号、里程和价格。所以您有
public class car
{
public string maker { get; set; }
public string model { get; set; }
public int mileage { get; set; }
public int price { get; set; }
}
public class carDealer
{
public string description { get; set; }
public List<car> carList { get; set; }
}
public class dealersList
{
public List<carDealer> list { get; set; }
}
您可以从数据库获取数据,我的示例只是硬编码了一些值。
重要的是,最终您将拥有一个 carDealer
类列表作为结果返回。您的主要管理器类看起来大致如下
public class componentManager
{
private componentBusinessLogic _bl = new componentBusinessLogic();
//Just a traffic manager
public dealersList getDealers()
{
return _bl.getDealers();
}
}
您的 DLL 几乎完成了,您的检索经销商列表的组件。您甚至可以稍微修改一下这个类并接受一个 zipCode
参数并据此检索,但为了方便本文,我们将就这样保留,只检索所有经销商。
现在是时候创建您的 VB6 项目将使用的互操作流量控制器了。您可以使用 Visual Basic .NET 项目中的 COM 类
来完成此操作。所以创建一个新的 VB.NET 类库项目。这基本上会为您构建一个即用型接口,您只需创建一个介于您的 C# 类和您的 VB6 项目之间的流量管理器。我们以后称之为 Wrapper Component(包装器组件)。
类似
Public Function GetDealers() As dealerList
'Just a traffic manager
Return _bl.getDealers()
End Function
这里有一个棘手的问题。您可以将您的 carDealer
类声明为 List
(of car
)对吧?
答案是否定的... VB6 不支持泛型,那么该怎么办?数组?不完全是,它们不像泛型那样是动态的。解决方案:Collection。
顺便说一句... 上面代码片段中的 _bl
是我的包装器业务逻辑的一个实例,它包含应用此更改的逻辑,从 <List>CarDealer
到 Collection。
因此,您需要稍微更改您的类,并且还需要在它们中包含一些指令,以便 VB6 可以看到它们,例如
Imports System.Runtime.InteropServices
<ClassInterface(ClassInterfaceType.AutoDual)> _
Public Class car
#Region "Fields"
Private _maker As String
Private _model As String
Private _mileage As Integer
Private _price As Integer
#End Region
#Region "Properties"
Public Property Maker() As String
Get
Return _maker
End Get
Set(ByVal value As String)
_maker = value
End Set
End Property
'Build the rest of the properties here
#End Region
End Class
<ClassInterface(ClassInterfaceType.AutoDual)> _
Public Class carDealer
#Region "Fields"
Private _description As String
'IMPORTANT -----------------------------
'add the word New to this declaration to avoid
'"Object reference not set to an instance of an object" Error
Private _carList As New Collection
#End Region
#Region "Properties"
Public Property Description() As String
Get
Return _description
End Get
Set(ByVal value As String)
_description = value
End Set
End Property
Public Property CarList() As Collection
Get
Return _carList
End Get
Set(ByVal value As Collection)
_carList = value
End Set
End Property
#End Region
End Class
<ClassInterface(ClassInterfaceType.AutoDual)> _
Public Class dealerList
Private _list As New Collection
Public Property List() As Collection
Get
Return _list
End Get
Set(ByVal value As Collection)
_list = value
End Set
End Property
End Class
调用 C# 项目。Component
是 C# 项目的命名空间。
Dim CM As New Component.componentManager
Dim tDealerList As New Component.businessEntities.dealersList
tDealerList = CM.getDealers()
用您的头脑将 C# 类型转换为您在此项目中声明的 VB 类型,仅此而已,遍历 tDealerList
中的 list
属性,创建一个 VB carDealer
实例,填充它并将其添加到新的 collection 中。最后,这个 collection 将成为您 VB dealierList
中的列表。大致如下
For Each tDealer As Component.businessEntities.carDealer In tDealerList.list
'Make the new type carDealer from this project
Dim rCarDealer As New carDealer
'Get the description from the Component c# project type
rCarDealer.Description = tDealer.description
Dim rCars As New Collection
For Each tCar As Component.businessEntities.car In tDealer.carList
rCars.Add(New car(tCar.maker, tCar.model, tCar.mileage, tCar.price))
Next
rCarDealer.CarList = rCars
rCars = Nothing
rList.List.Add(rCarDealer)
Next
您完成了。
您可以构建您的应用程序。在命令行中使用以下命令注册您的 DLL 以进行互操作
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\regasm
"ComponentWrapper.dll" /tlb /codebase
C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\gacutil -i ComponentWrapper.dll
这将创建一个 *.tlb 文件;打开您的 VB6 项目并使您的 tlb 文件具有引用。您将无法引用 DLL,所以不要尝试。
现在在 VB6 中,您基本上可以这样做
Dim list As New ComponentWrapper.dealerList
Dim cManager As New ComponentWrapper.CWManager
Set list = cManager.GetDealers()
从这里开始... 就看您的了。
关注点
这一切中最酷的地方在于,您现在拥有了一个您的未来 .NET 应用程序可以使用,并且处于过渡期的 VB6 应用程序也可以使用包装器的组件,您只需创建包装器组件即可完成。
我在这段学习过程中遇到的最令人沮丧的部分是泛型无法在 VB6 中使用。最终我发现 VB6 中唯一足够灵活的是 collection。我知道有时使用它可能看起来是一个缺点,但我认为在这种特殊情况下,以及我确定还有许多其他情况,它非常有用。
在将 VB6 应用程序重写为 .NET 时,还有许多其他指南需要遵循,如果您正在创建供 .NET 应用程序和 VB6 应用程序使用的通用 DLL,我发现以下链接对于进行此比较非常有帮助
历史
- 2009 年 1 月 8 日:初始发布