VB.NET:如何引用VB.NET模块?

20
我获得了一个Utility模块,因为VB.NET没有像C#一样的静态类,Module是VB.NET中的静态类。我使用模块的原因是我正在使用扩展方法,只能在模块中使用。
如果我把我的代码放在一个类中,我就可以引用它而没有任何问题。可能的原因是什么?我错过了C#。
编辑:该模块位于名为Utility的类库中。

你误解了 VB.Net 的能力。模块不是 Shared/Static 类,它们对于可以在任何地方使用的 Namespace 方法是全局的。它们通常是 Type 抽象的,而不是 Extensions。函数、Subs 甚至 Extensions 都存在于 OOP 气泡之外,由 @Konrad-Rudolph 描述。 - GoldBishop
另一个需要注意的是,对于未来的观众来说...模块的名称在库之间不能重名。名称必须在使用之间唯一。 - GoldBishop
6个回答

55

您需要将该模块标记为公共模块。


9

我无法引用这个模块,但如果我把我的代码放在一个类中,就可以毫无问题地引用它。有人知道为什么吗?

因为VB中的模块不是类,不能用于实例化对象。相反,它们类似于命名空间,与命名空间的区别在于命名空间不能直接包含函数。因此,模块的原因是提供一种逻辑上分组函数的方式,这些函数不属于某个类。

当你考虑到并非所有东西都逻辑上属于一个类时,这就很有意义了。考虑一下System.Math。除了奇怪的面向对象纯洁主义之外,没有任何理由使其成为一个类。

顺便说一句,你在C#中也不能引用静态类,至少如果我正确理解你所说的“引用”的含义的话。也许你可以澄清一下。


我一直认为,但是把它放在“共享”类中有什么问题吗?如果一个函数接收数据,进行计算并输出结果,除了输入数据之外不使用或修改任何其他内容,为什么不能将其放在一个类中并标记为“共享”? - SqlRyan
1
问题是:为什么应该这样做?类有什么优势?面向对象编程作为一种范式只有在具有优势时才有用。没有数据(也没有位置作为标记类型)的类没有任何作用。 - Konrad Rudolph
@SqlRyan,为什么“通用”的东西要和类的范围绑定在一起呢?为什么不放在命名空间中呢?或者更好的方法是,直接放在库中。如果它与类或命名空间无关,为什么要将其限制在一个范围内?模块是一种在库范围内创建方法的方式,而不会严格地与不能正确描述其用途的对象绑定在一起。 - GoldBishop

8

.NET编译器可以将任何类型的语言语法转换为.NET等效语法。有时存在一对一的对应关系,有时则没有。

通过使用.NET Reflector,您可以看到编译器实际上正在做什么。

VB.NET中,模块的存在是由于继承自Visual BASIC和Microsoft BASIC的遗产所致。

VB.NET编译器将采取此操作

Public Module CoreModule
    Dim R As New System.Random(CInt(Microsoft.VisualBasic.Timer))
    Public Function D(ByVal Roll As Integer) As Integer
        Return R.Next(0, Roll) + 1
    End Function

    Public Function _1D6() As Integer
        Return D(6)
    End Function

    Public Function _2D6() As Integer
        Return D(6) + D(6)
    End Function

    Public Function _3D6() As Integer
        Return D(6) + D(6) + D(6)
    End Function

    Public Function _4D6() As Integer
        Return D(6) + D(6) + D(6) + D(6)
    End Function

    Public Function CRLF() As String
        Return Microsoft.VisualBasic.ControlChars.CrLf
    End Function
End Module

把它转换成这样(为了简洁起见,代码被省略了)。
Public NotInheritable Class CoreModule
    ' Methods
    Shared Sub New()
    Public Shared Function _1D6() As Integer
    Public Shared Function _2D6() As Integer
    Public Shared Function _3D6() As Integer
    Public Shared Function _4D6() As Integer
    Public Shared Function CRLF() As String
    Public Shared Function D(ByVal Roll As Integer) As Integer

    ' Fields
    Private Shared R As Random
End Class

在C#中的等效代码如下。
public sealed class CoreModule
{
    // Fields
    private static Random R;

    // Methods
    static CoreModule();
    public static int _1D6();
    public static int _2D6();
    public static int _3D6();
    public static int _4D6();
    public static string CRLF();
    public static int D(int Roll);
}

重要的是发出的CIL能够正确地完成工作。

这种能力是为什么许多老的Visual BASIC 6程序员对MS对该语言的更改感到非常恼火的主要原因。例如,关键字Integer发出Int32而不是Int16。

只要模块被声明为public,就可以将其暴露给引用原始程序集的其他程序集。


澄清一下,BasicA从未归属于微软...微软的所有权始于QBasic。Basic - GoldBishop
不错!这帮助我转换了一个模块,以便我可以从成员方法引用其类型,以使用Serilog记录类名。 - Daniel P

1

也许方法/子程序不是公共的?我曾经遇到过这个问题,它只允许访问类内部的本地代码,但如果它在类外部并标记为“私有”,则无法访问。


0
Imports System.Web
Imports System.Web.UI

Module ResponseHelper

    <System.Runtime.CompilerServices.Extension()> _
    Public Sub Redirect(ByVal response As Net.HttpWebResponse, _
                        ByVal url As String, ByVal target As String, _
                        ByVal windowFeatures As String)

        If String.IsNullOrEmpty(target) Or _
           target.Equals("_self", StringComparison.OrdinalIgnoreCase) And _
           String.IsNullOrEmpty(windowFeatures) Then
            response.Redirect(url, target, windowFeatures)
        Else
            Dim page As Page = CType(HttpContext.Current.Handler, Page)
            If page Is Nothing Then
                Throw New InvalidOperationException("Cannot redirect to new window outside Page context.")
            End If
            url = page.ResolveClientUrl(url)
            Dim script As String
            If String.IsNullOrEmpty(windowFeatures) Then
                script = "window.open(""{0}"", ""{1}"", ""{2}"";"
            Else
                script = "window.open(""{0}"", ""{1}"");"
            End If
            script = String.Format(script, url, target, windowFeatures)
            ScriptManager.RegisterStartupScript(page, GetType(Page), "Redirect", script, True)

        End If
    End Sub

End Module

你是在尝试用JavaScript函数覆盖response.redirect吗?> . < - Shawn

-1

我不明白你在问什么。

VB.NET 确实有静态类,就像C#一样,因为在VB.NET中,Module 就是一个static class。它们完全相同。任何你可以使用静态类的功能都可以通过Module实现。也许你没有正确标记Public/Private/Protected权限?


4
@Joel:不,它们在语言层面上并不相同。具体而言,模块会隐式地将它们的名称导入到当前命名空间中。这意味着在引用模块名称时,您不必使用模块名称作为前缀(前提是导入了模块所处的命名空间)。 - Konrad Rudolph

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接