【问题标题】:Classes vs. Modules in VB.NETVB.NET 中的类与模块
【发布时间】:2010-10-27 06:20:15
【问题描述】:

在 VB.NET 中使用模块而不是具有共享成员函数的类是否被认为是一种可接受的做法?

我倾向于避免使用模块,因为它们感觉像是 Visual Basic 6.0 的剩余部分,并且似乎不再适合。另一方面,使用模块和只有共享成员的类之间似乎没有太大区别。我并不经常需要它们,但有时它们会提供简单的解决方案。

我很想知道您是否有任何意见或偏好。

【问题讨论】:

  • 关于模块的一个有趣之处在于,默认情况下,内部声明的方法和函数具有模块的保护级别,这意味着如果您忘记显式添加Private 限定符,您可能会无意中使方法可用。在一个类中,默认保护级别是私有的,除非您意识到这一点,否则这可能会造成混淆。

标签: vb.net


【解决方案1】:

  • 类可以被实例化为对象
  • 每个实例化对象的对象数据分别存在。
  • 类可以实现接口
  • 在类中定义的成员在类的特定实例内并且仅在对象的生命周期内存在
  • 要从类外部访问类成员,您必须使用 Object.Member 格式的完全限定名称

模块

  • 模块不能实例化为对象,因为标准模块的数据只有一份副本,当你的程序的一部分改变标准模块中的公共变量时,它将对整个程序。
  • 默认情况下,模块中声明的成员可公开访问
  • 任何可以访问该模块的代码都可以访问它。
  • 这意味着标准模块中的变量实际上是全局变量,因为它们在项目中的任何位置都可见,并且在程序的整个生命周期中都存在。

【讨论】:

    【解决方案2】:

    如果您正在创建扩展方法,您必须使用模块(而不是类)。在 VB.NET 中,我不知道其他选项。

    由于我自己对模块有抵抗力,我只是花了几个小时试图弄清楚如何添加一些样板代码来解决嵌入式程序集,结果发现Sub New()(模块)和Shared Sub New()(类)是等价的。 (我什至不知道模块中有一个可调用的Sub New()!)

    所以我只是将EmbeddedAssembly.LoadAddHandler AppDomain.CurrentDomain.AssemblyResolve 行扔在那里,鲍勃就成了我的叔叔。

    附录:我还没有 100% 地检查它,但我有一种暗示,Sub New() 在模块中的运行顺序与在类中的运行顺序不同,这只是事实我不得不将一些声明从外部移动到内部方法以避免错误。

    【讨论】:

      【解决方案3】:

      模块可以很好地存储枚举和一些全局变量、常量和共享函数。它非常好,我经常使用它。声明的变量在整个项目中都是可见的。

      【讨论】:

        【解决方案4】:

        可以使用ModuleModule 不能替代 ClassModule 服务于它自己的目的。 Module 的目的是用作容器

        • 扩展方法,
        • 不特定于任何Class 的变量,或
        • 不适合任何Class 的变量。

        Module 不像 Class,因为你不能

        • Module继承,
        • Module 实现Interface
        • 也不创建Module 的实例。

        Module 中的任何内容都可以在 Module 程序集中直接访问,而无需通过名称引用 Module。默认情况下,Module 的访问级别为 Friend

        【讨论】:

          【解决方案5】:

          当我的一个 VB.NET 类具有所有共享成员时,我要么将其转换为具有匹配(或其他适当)命名空间的模块,要么使该类不可继承且不可构造:

          Public NotInheritable Class MyClass1
          
             Private Sub New()
                'Contains only shared members.
                'Private constructor means the class cannot be instantiated.
             End Sub
          
          End Class
          

          【讨论】:

          • 下面是命名空间模块的语法:Imports <whatever> 如果你有任何导入,Namespace MyCoolModulePublic Module MyCoolModulewithout Shared>,@ 987654326@, End Namespace.
          【解决方案6】:

          Modules 是 C# static 类的 VB 对应项。当您的类仅为辅助函数和扩展方法而设计并且您希望允许继承实例化时,您可以使用@987654324 @。

          顺便说一句,使用Module 并不是很主观,它不推荐使用。实际上,您必须在适当的时候使用Module。 .NET Framework 本身多次执行此操作(例如System.Linq.Enumerable)。声明扩展方法需要使用Modules。

          【讨论】:

          • 非常正确,虽然我可以使用私有构造函数来防止实例化和 NotInheritable 修饰符。比普通的旧模块略丑,但具有相同的效果。感谢您在框架中使用模块的指针;我会调查的。
          • 在底层,它们只是被编译为具有 [StandardModule] 属性的类。此外,使用 Module 会迫使您不要在那里有非共享的东西,这是一件好事。
          • 模块与 C# 中的静态类不同。如果模块中的方法位于导入的命名空间中,则它们实际上是全局的。
          • @JaredPar:我的措辞可能不好。我应该说 VB 对应于 C# 静态类。从那句话中,我的意思是说在 C# 中编写静态类时使用模块是有意义的。
          • @Chiwda 请参阅msdn.microsoft.com/en-us/library/bb384936.aspx:“扩展方法只能在模块内声明。”
          【解决方案7】:

          模块绝不会被弃用,并且在 VB 语言中大量使用。例如,这是在 VB.Net 中实现扩展方法的唯一方法。

          具有静态成员的模块和类之间存在巨大差异。只要 Module 在当前命名空间中可用,在 Module 上定义的任何方法都可以全局访问。实际上,模块允许您定义全局方法。这是只有共享成员的类无法做到的。

          这是一个我在编写与原始 COM 接口互操作的 VB 代码时经常使用的快速示例。

          Module Interop
            Public Function Succeeded(ByVal hr as Integer) As Boolean
              ...
            End Function
          
            Public Function Failed(ByVal hr As Integer) As Boolean
              ...
            End Function
          End Module
          
          Class SomeClass
            Sub Foo()
              Dim hr = CallSomeHrMethod()
              if Succeeded(hr) then
                ..
              End If
            End Sub
          End Class
          

          【讨论】:

          • 扩展方法...我一直想使用的另一个很好的功能,但从未真正开始使用 - 嗯,这给了我另一个好机会。我确实对全局范围有所了解,全局可用的方法当然很方便,但我对过度使用它们感到有些不安。无论如何,到目前为止所有的答案都告诉我,我不应该放弃模块。有充分的理由在适当的情况下使用它们。
          【解决方案8】:

          我认为最好避免使用模块,除非您将它们放入单独的命名空间中。因为在 Intellisense 中,模块中的方法将在该命名空间的任何地方都可见。

          因此,您最终会在任何地方弹出MyMethod() 而不是ModuleName.MyMethod(),这会使封装无效。 (至少在编程层面)。

          这就是为什么我总是尝试使用共享方法创建类,看起来好多了。

          【讨论】:

          • 同意,我目前正在开发一个带有类和模块的旧程序(可能是 VB6 到 VB.NET 1 的端口)。大约十个不同的模块中有数百个全局变量、子函数和函数,要找出是什么起源于哪里以及如何修改它是地狱。
          • 好的,这已经很老了,但与我的问题有关。我不是一个 VB 人,但我必须使用它。我试图分解一个大类(> 46,000 行),因为 IntelliSense/ReSharper 刚刚死去。我发现使用模块并且只是将大块功能剥离到他们自己的模块中似乎是可行的,但我想知道我是否应该给每个模块自己的命名空间。那有必要吗?也就是说,它会仅通过模块来加速 IntelliSense,还是命名空间会帮助更多?
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-08
          • 2015-03-10
          • 1970-01-01
          • 1970-01-01
          • 2016-03-17
          • 2011-10-18
          相关资源
          最近更新 更多