VB.NET 类或模块的用途是什么?

2024-06-18

这里是新手酱...所以,我试图找到答案,但找不到。

拥有类或模块的目的是什么?我读到的所有内容都试图告诉我它是什么,但不是它的用途。为什么我需要制作一个?

我读到的所有内容似乎都对阅读教程的人做出了假设,就好像我知道很多一样。


模块实际上与仅包含共享成员的类非常相似。事实上,在 C# 中,不存在“模块”这样的构造。如果没有至少一个模块或类,您就无法编写任何应用程序,因此我怀疑您真正的问题不是“为什么使用类和模块”,而是“为什么使用多个类和模块以及何时适合启动新的类和模块” 。由于模块和类本质上是相同的东西,所以我将只关注为什么你会有多个类。创建新类本质上有四个主要原因:

  1. 将数据存储在离散项目中
  2. 组织你的代码
  3. 在代码中提供接缝
  4. 将代码分层并支持 n 层

现在,让我们更详细地看看每一项:

将数据存储在离散项目中

通常,您需要存储有关单个项目的多个数据,并将该数据作为单个对象在方法之间传递。例如,如果您编写一个与某人一起工作的应用程序,您可能需要存储有关该人的多个数据,例如他们的姓名、年龄和头衔。显然,您可以将这三个数据存储为三个单独的变量,并将它们作为单独的参数传递给方法,例如:

Public Sub DisplayPerson(name As String, age As Integer, title As String)
    Label1.Text = name
    Label2.Text = age.ToString()
    Label3.Text = title
End Sub

但是,将所有数据作为单个对象传递通常更方便,例如,您可以创建一个MyPersonClass, 像这样:

Public Class MyPersonClass
   Public Name As String
   Public Age As Integer
   Public Title As String
End Class

然后您可以在单个参数中传递有关一个人的所有数据,如下所示:

Public Sub DisplayPerson(person As MyPersonClass)
    Label1.Text = person.Name
    Label2.Text = person.Age.ToString()
    Label3.Text = person.Title
End Sub

通过这样做,将来修改你的人会变得更加容易。例如,如果您需要添加存储人员技能的功能,并且尚未将人员数据放入类中,则必须转到传递人员数据的代码中的每个位置并添加附加参数。在大型项目中,找到所有需要修复的地方可能非常困难,这可能会导致错误。然而,当您开始需要存储多人列表时,对类的需求就变得更加明显。例如,如果您需要存储 10 个不同人的数据,则需要一个变量列表或数组,例如:

Dim names(9) As String
Dim ages(9) As Integer
Dim titles(9) As String

当然,这一点并不明显names(3) and age(3)两者都存储同一个人的数据。这是你必须知道的事情,或者你必须把它写在评论中,这样你就不会忘记。然而,当您有类来存储一个人的所有数据时,这会更干净、更容易做到:

Dim persons(9) As Person

现在,很明显persons(3).Name and persons(3).Age都是同一个人的数据。这样,它就是自我记录的。不需要任何评论来澄清你的逻辑。因此,代码将不再那么容易出现错误。

通常,类不仅包含特定项目的数据,还包含作用于该数据的方法。这是一个方便的机制。例如,您可能想添加一个GetDesciptionperson 类的方法,例如:

Public Class MyPersonClass
   Public Name As String
   Public Age As Integer
   Public Title As String

   Public Function GetDescription() As String
       Return Title & " " & Name
   End Function
End Class

然后你可以像这样使用它:

For Each person As MyPersonClass In persons
    MessageBox.Show("Hello " & person.GetDescription())
Next

我相信你会同意,这比这样做更干净、更容易:

For i As Integer = 0 To 9
    MessageBox.Show("Hello " & GetPersonDescription(title(i), names(i)))
Next

现在假设您想为每个人存储多个昵称。正如你可以很容易地看到的,persons(3).Nicknames(0)比一些疯狂的二维数组简单得多,例如nicknames(3)(0)。如果您需要存储有关每个昵称的多个数据,会发生什么情况?正如您所看到的,不使用类会很快变得混乱。

组织你的代码

当您编写一个冗长的程序时,如果您没有正确组织代码,它可能会很快变得非常混乱,并导致非常错误的代码。在这场与意大利面条式代码的战斗中,最重要的武器是创建更多的类。理想情况下,每个类仅包含逻辑上直接相关的方法。每个新类型的功能都应该分解为一个新的、命名良好的类。在一个大型项目中,这些类应该进一步组织到单独的命名空间中,但如果你不至少将它们拆分成类,那么你真的会把事情弄得一团糟。例如,假设您将以下方法全部放入同一个模块中:

  • GetPersonDescription
  • GetProductDescription
  • FirePerson
  • SellProduct

我相信您会同意,如果将这些方法分解为单独的类,那么遵循代码会更容易,例如:

  • Person
    • GetDescription
    • Fire
  • Product
    • GetDescription
    • Sell

这只是一个非常非常简单的例子。当您有数千个方法和变量处理许多不同的项目和不同类型的项目时,我相信您可以轻松想象为什么类对于帮助组织和自我记录代码很重要。

在代码中提供接缝

这个可能有点高级,但它非常重要,所以我将尝试用简单的术语来解释它。假设您创建了一个跟踪记录器类,它将日志条目写入跟踪日志文件。例如:

Public Class TraceLogger
    Public Sub LogEntry(text As String)
        ' Append the time-stamp to the text
        ' Write the text to the file
    End Sub
End Class

现在,假设您希望记录器类能够写入文件或数据库。此时很明显,将日志条目写入文件实际上是一种单独的逻辑类型,它应该一直位于其自己的类中,因此您可以将其分解为单独的类,如下所示:

Public Class TextFileLogWriter
    Public Sub WriteEntry(text As String)
        ' Write to file
    End Sub
End Class

现在,您可以创建一个公共接口并在两个不同的类之间共享它。这两个类都将处理写入日志条目,但它们将以完全不同的方式执行功能:

Public Interface ILogWriter
    Sub WriteEntry(text As String)
End Interface

Public Class TextFileLogWriter
    Implements ILogWriter

    Public Sub WriteEntry(text As String) Implements ILogWriter.WriteEntry
        ' Write to file
    End Sub
End Class

Public Class DatabaseLogWriter
    Implements ILogWriter

    Public Sub WriteEntry(text As String) Implements ILogWriter.WriteEntry
        ' Write to database
    End Sub
End Class

现在,您已经将该数据访问逻辑分解为自己的类,您可以像这样重构您的记录器类:

Public Class TraceLogger
    Public Sub New(writer As ILogWriter)
        _writer = writer
    End Sub

    Private _writer As ILogWriter

    Public Sub LogEntry(text As String)
        ' Append the time-stamp to the text
        _writer.WriteEntry(text)
    End Sub
End Class

现在,您可以重复使用TraceLogger在更多情况下可以调用该类,而无需接触该类。例如,你可以给它一个ILogWriter将条目写入 Windows 事件日志、电子表格、甚至电子邮件的对象 - 所有这些都无需触及原始内容TraceLogger班级。这是可能的,因为您已经创建了seam条目格式和条目书写之间的逻辑。

格式不关心条目如何记录。它所关心的是如何格式化条目。当它需要写入和输入时,它只是要求一个单独的写入器对象来完成该部分工作。该作者实际上在内部如何做以及做什么是无关紧要的。类似地,编写者并不关心条目的格式如何,它只是期望传递给它的任何内容都是需要记录的已格式化的有效条目。

正如您可能已经注意到的,不仅是TraceLogger现在可重复使用以写入任何类型的日志,而且写入器也可重复使用以将任何类型的日志写入这些类型的日志。您可以重复使用DatabaseLogWriter例如,写入跟踪日志和异常日志。

关于依赖注入的一点抱怨

请稍微幽默一下,因为我将这个答案写得更长一些,并对一些对我来说很重要的事情进行了咆哮……在最后一个例子中,我使用了一种称为依赖注入(DI)的技术。它被称为依赖注入,因为 writer 对象是依赖性记录器类的依赖项对象通过构造函数注入到记录器类中。您可以通过执行以下操作来完成类似的事情,而无需依赖注入:

Public Class TraceLogger
    Public Sub New(mode As LoggerModeEnum)
        If mode = LoggerModeEnum.TextFile Then
            _writer = New TextFileLogWriter() 
        Else
            _writer = New DatabaseLogWriter() 
        End If
    End Sub

    Private _writer As ILogWriter

    Public Sub LogEntry(text As String)
        ' Append the time-stamp to the text
        _writer.WriteEntry(text)
    End Sub
End Class

但是,正如您所看到的,如果您这样做,现在每次创建新类型的编写器时都需要修改该记录器类。然后,仅仅为了创建一个记录器,您就必须引用每种不同类型的编写器。当您以这种方式编写代码时,很快,每当您包含一个类时,您突然就必须引用整个世界来完成一项简单的任务。

依赖注入方法的另一种替代方法是使用继承来创建多个TraceLogger课程,每种类型的作家一个:

Public MustInherit Class TraceLogger
    Public Sub New()
        _writer = NewLogWriter() 
    End Sub

    Private _writer As ILogWriter

    Protected MustOverride Sub NewLogWriter()

    Public Sub LogEntry(text As String)
        ' Append the time-stamp to the text
        _writer.WriteEntry(text)
    End Sub
End Class

Public Class TextFileTraceLogger
    Inherits TraceLogger

    Protected Overrides Sub NewLogWriter()
        _Return New TextFileLogWriter() 
    End Sub
End Class

Public Class DatabaseTraceLogger
    Inherits TraceLogger

    Protected Overrides Sub NewLogWriter()
        _Return New DatabaseLogWriter() 
    End Sub
End Class

像这样使用继承来实现,比模式枚举方法更好,因为您不必引用所有数据库逻辑来记录到文本文件,但是,在我看来,依赖项注入更干净、更灵活。

回到逻辑接缝总结

因此,总而言之,逻辑中的接缝对于代码的可重用性、灵活性和可互换性非常重要。在小型项目中,这些事情并不是最重要的,但随着项目的增长,清晰的接缝可能变得至关重要。

创建接缝的另一个大好处是它使代码更加稳定和可测试。一旦您知道TraceLogger有效,能够扩展它以供将来使用有一个很大的优势,例如将日志写入电子表格,而不必接触实际的TraceLogger班级。如果您不必接触它,那么您就不会冒引入新错误并可能危及已使用它的其余代码的风险。此外,单独测试每段代码也变得更加容易。例如,如果您想测试TraceLogger类,您可以在测试中使用一个假的 writer 对象,该对象仅记录到内存、控制台或其他东西。

将您的代码划分为多个层并支持 N 层

一旦您将代码正确地组织到单独的类中,其中每个类仅负责一种类型的任务,那么您就可以开始将您的类分组到layers。层只是代码的高级组织。从技术上讲,该语言没有任何特定的东西可以使某些东西成为一个层。由于语言中没有直接说明每一层开始和结束位置的内容,因此人们通常会将每一层的所有类放入单独的命名空间中。因此,例如,您可能拥有如下所示的命名空间(其中每个命名空间都是一个单独的层):

  • MyProduct.Presentation
  • MyProduct.Business
  • MyProduct.DataAccess

通常,您总是希望代码中至少有两层:表示层或用户界面层以及业务逻辑层。如果您的应用程序进行任何数据访问,那么通常也将其放在自己的层中。每层应尽可能独立且可互换。所以,举例来说,如果我们的TraceLogger上面示例中的类位于业务层,它应该可以被任何类型的 UI 重用。

层通过提供进一步的组织、自文档、可重用性和稳定性来扩展之前的所有主题。然而,层的另一个主要好处是,将应用程序分成多个层变得更加容易。例如,如果您需要将业务和数据访问逻辑转移到 Web 服务中,如果您已经将代码干净地编写到定义的层中,那么这样做将非常简单。然而,如果所有这些逻辑都是混合在一起且相互依赖的,那么尝试将数据访问和业务逻辑分解为一个单独的项目将是一场噩梦。

我要说的结束了

简而言之,你永远不会need创建多个类或模块。它永远都会是possible在单个类或模块中编写整个应用程序。毕竟,在面向对象语言被发明之前,整个操作系统和软件套件就已经开发出来了。然而,面向对象编程(OOP)语言如此流行是有原因的。对于许多项目来说,面向对象是非常有益的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

VB.NET 类或模块的用途是什么? 的相关文章

  • 将本地 HTML 文件/代码导入 Web 浏览器

    我正在尝试让本地 HTML 文件显示在WebBrowser在 VB NET 程序中 我正在使用下面的代码 但它似乎不起作用 我不明白为什么 first method WebBrowser1 Navigate index html secon
  • 是否可以为 Visual Studio 2010 编写一个调试器可视化工具来显示 64 位 .NET 程序?

    是否可以为 Visual Studio 2010 编写一个调试器可视化工具来显示 64 位 NET 程序的数据 我已经为 32 位编程编写了它们 但我无法设法使用或编译它们以用于 64 位应用程序 有什么建议么 我刚刚经历过同样的问题 我使
  • VB - 如何读取和写入二进制文件?

    如何从任何文件读取原始字节数组 Dim bytes as Byte 然后将该字节数组写回到新文件中 我需要它作为字节数组来在两者之间进行一些处理 我目前正在使用 To read Dim fInfo As New FileInfo dataP
  • VB.NET 中的静态方法实现

    我很困惑Static在 VB NET 中的实现 在 C 中 我们可以创建静态类和静态方法来为我们的应用程序编写实用方法 现在 VB NET 让我们创建Module代替静态类 如果我们在模块中创建一个方法 默认情况下它会变成静态的 但在我的应
  • Vb中读取USB存储设备的序列号

    是否可以使用VB读取USB驱动器的序列号 这将为您提供 net 中驱动器的信息 包括 USB 设备 只需导入这些 导入脚本 导入系统 IO Private Class USBsn Private Sub Button1 Click ByVa
  • Newtonsoft.Json.JsonReaderException

    我的 Newtonsoft Json 有问题 我正在尝试从 URL 解析 JSON 但收到错误 这是 JSON ID 0 Nome we Data 2013 09 16 Orario 00 00 16 Prestazione dfg Sta
  • WithEvents(句柄)与 AddHandler 之间的区别

    我搜索了关键字使用的差异Handles http msdn microsoft com en us library 6k46st1y aspx代替添加处理程序 http msdn microsoft com en us library 7t
  • 如何使用c#/VB.NET在word中插入书签

    我正在尝试使用 C 在 Word 文档中添加书签 但它不起作用 而且我在 msdn 文档和互联网上都找不到任何帮助 这就是我正在尝试做的事情 我正在阅读 Word 文档 然后在该文档中搜索关键字 然后将该文本转换为超链接 效果很好 现在 我
  • 什么可能会在一台服务器上导致此错误,而在另一台服务器上则不会?

    我们有一个连接到外部 Web 服务的 ASP Net 网站 几天前它突然停止工作 基本代码是这样的 Try request New ExternalWebService ProcessRequestService Error occurs
  • 重写某些 .Net Framework 控件的绘制以更改其边框颜色?

    SCENARIO 我正在使用第三方 Windows 视觉主题 当我看到我的应用程序时 它看起来像这样 但是当我使用正常的Aero主题 它看起来到处都有可怕的白色边框 QUESTION 我知道应用程序中使用的配色方案取决于视觉风格 但是 我可
  • 如何使用正则表达式验证带有可选百分比符号的小数?

    正如问题的标题 我需要使用以下值验证正则表达式 最多 2 个小数位和 9 个整数 带有可选的百分比符号 Valid 10 0 1111111 12 15 2 10 2 3 Invalid 12 02 123456789123 123 I t
  • 在 VB.Net 中将字节数组转换为整数

    我想知道在 vb net 中将字节数组 长度 4 转换为整数的最佳方法是什么 我知道 BitConverter 但执行函数调用来执行应该可以通过复制 4 字节内存来完成的操作似乎相当浪费 同样 将单 双精度数从二进制表示形式转换为单 双精度
  • 确定哪个进程锁定了文件

    我有一个在本地运行良好的单元测试 但上传到 TeamCity 构建服务器时失败 并显示 该进程无法访问该文件 因为它正在被另一个进程使用 在我在测试中做任何事情之前 我检查设置是否有文件 存在 如果存在尝试删除它 这会失败并出现相同的错误
  • 错误:表达式不产生值

    我尝试将以下 C 代码转换为 VB NET 但在编译代码时出现 表达式不产生值 错误 C Code return Fluently Configure Mappings m gt m FluentMappings AddFromAssemb
  • 如何在 VB.NET 中对数组进行 JSON 编码?

    我需要为我正在使用的例程传回 JSON 结果 在VB NET 数组如何进行JSON编码 Dim serializer as New JavaScriptSerializer Dim arrayJson as String serialize
  • Enum.GetName 与 Enum.ToString

    对于这个枚举 Enum MyEnum Value End Enum 有两种方法获取名称表示Value of MyEnum Value Enum GetName GetType MyEnum MyEnum Value aka Enum Get
  • 在vb.net中将base64解码为图像

    我一直在互联网上搜索 但没有找到答案 你想告诉我如何解码base64 to be Image像折线图一样 我一直在尝试从base64 to Byte首先数组并从Byte数组到Image Private Function convertbyt
  • VB.net 将窗口置于前面

    我需要在 VB net 2010 中使用什么代码来设置窗口到屏幕前面 我想要实现的是显示紧急警报类型 它是一种表单 由于某些原因我没有使用消息框 有人建议使用以下代码 但这不起作用 Private Sub frmMessage Load B
  • SSDT 单元测试:从配置文件读取 SQL Server 单元测试设置时发生错误

    我在 Visual Studio 2013 professional 中创建了一个数据库项目 然后通过右键单击存储过程之一并选择来添加单元测试创建单元测试 选择创建一个新的VB测试项目 然后右键单击新创建的测试项目并选择SQL Server
  • 在运行时从调试可视化工具中检测源语言

    我正在写一个Visual Studio 的调试可视化工具 https github com zspitz ExpressionToString visual studio debugger visualizer for expression

随机推荐

  • 如何使用 NHibernate 将实体分布在多个表上?

    我有预先存在的表 使用一种开放模式 我有一个项目表 各种实体被分类为项目 然后将属性存储在项目属性表中 单个实体类型可能具有存储在多个表中的字段 我们公开带有视图的实体 所以 大多数实体对应一个视图 然后当我们插入 更新时 我们必须系统地更
  • 构建视图模型的最佳方法是什么?

    我正在使用带有实体框架的 asp net mvc 并开始学习 DDD 我正在从事包含调查的项目 这是我的域模型 public class Survey public int SurveyID get set public string Na
  • 将 iCloud 存储迁移到本地存储并确保每次应用程序启动时数据都在那里

    基于这里的问题 将 iCloud 数据迁移到本地存储并阻止 iCloud 继续响应 https stackoverflow com questions 25186787 migrate icloud data to local store
  • 如何通过 Google Sheets API 进行基本写作?

    在使用 Swift 学习 Google Sheets API 的过程中 我想将单个范围写入电子表格 调查iOS 快速入门指南 https developers google com sheets quickstart ios ver swi
  • JavaScript 计算从今天到 7 天前的日期

    我正在计算从今天开始的日期前 12 天 但它不会返回正确的日期 例如 对于今天的日期 11 11 2013 mm dd yyyy 它返回 10 30 2013 而它应该返回 10 31 2013 这是代码 var d new Date d
  • 模块函数中使用的 $_ 变量为空 (PowerShell)

    这里有一个问题要问你 我有这个功能 function Set DbFile param Parameter ValueFromPipeline true System IO FileInfo InputObject Parameter Va
  • Java如何从字符串实例化一个类[重复]

    这个问题在这里已经有答案了 可能的重复 在 Java 中从变量创建新类 https stackoverflow com questions 1268817 create new class from a variable in java 我
  • 使用包含和不包含的 Linq 查询

    我正在尝试从数据库中获取记录 它应该 getrecords 其中名称包含 searchKey 并且名称不在 exceptTerms 数组中 并以逗号分隔 我怎样才能在 Linq 中做到这一点 Rows from u in DB Client
  • 命令“tinker”未定义

    从 5 3 升级到 5 4 后 请按照说明操作 为了继续使用 Tinker Artisan 命令 您还应该安装 laravel tinker 软件包 composer require laravel tinker 安装软件包后 您应该添加
  • C#中global::关键字的用法是什么?

    有什么用global C 中的关键字 什么时候我们必须使用这个关键字 从技术上来说 global不是关键字 它是所谓的 上下文关键字 它们仅在有限的程序上下文中具有特殊含义 并且可以在该上下文之外用作标识符 global每当有歧义或成员被隐
  • 关闭有效句柄时,AppVerifier 报告“无效句柄 - 代码 c0000008”

    我有一个简单的测试程序 在运行时会失败并出现异常AppVerifier 程序重复STD INPUT HANDLE然后尝试使用关闭它CloseHandle 该程序运行良好 无需AppVerifier返回TRUE for CloseHandle
  • 如何获取 CIFilter 类中的过滤器名称列表?

    我正在使用以下代码进行曝光调整及其工作 我需要锐化 降噪 高光 色温 阴影 模糊等滤镜名称 CIFilter filterWithName CIExposureAdjust keysAndValues inputImage imageVie
  • 将 clientsecret 转换为私钥

    我正在 AppEngine 中使用 Google Cloud Storage 并尝试使用 POST 表单将文件上传到 GCS 我遇到的问题是签署保单文件所需的步骤 我可以轻松获取 client secret 它是来自client secre
  • 从 ttyUSB0 写入和读取,无法得到响应

    我对 Linux tty 不太有经验 我的环境是带有丰富 USB 串行的 Raspbian 什么有效 stty F dev ttyUSB0 38400 cu l dev ttyUSB0 s 38400 cu to dev ttyUSB0作品
  • sigmoid 的导数

    我正在使用反向传播技术创建一个神经网络进行学习 我知道我们需要找到所使用的激活函数的导数 我正在使用标准 sigmoid 函数 f x 1 1 e x 我已经看到它的导数是 dy dx f x f x 1 f x 这可能是一个愚蠢的问题 但
  • 如果重复,则从数组中删除两个值 - JavaScript/jQuery

    我这里有一个数组 var myArr 1 1 2 5 5 7 8 9 9 现在我想删除重复的两个外观 所以想要的结果是not var myArr 1 2 5 7 8 9 but var myArr 2 7 8 基本上我知道如何删除重复项 但
  • GAE 上奇怪的 500 错误

    我今天开始在我的应用程序上收到此错误 根本不记得更改任何内容 每当我在本地尝试时它都工作正常 但部署后我会收到此错误 EXCEPTION java lang ClassNotFoundException se myApp server My
  • 为什么 Python 中的无分支函数和内置函数速度较慢?

    我发现了 2 个无分支函数 它们可以在 python 中查找两个数字的最大值 并将它们与 if 语句和内置 max 函数进行比较 我认为无分支或内置函数将是最快的 但最快的是 if 语句函数 有人知道这是为什么吗 以下是功能 If 语句 2
  • Java - 直观地拖动摆动元素

    有没有类似的解决方案http allen sauer com com allen sauer gwt dnd demo DragDropDemo DragDropDemo html PaletteExample http allen sau
  • VB.NET 类或模块的用途是什么?

    这里是新手酱 所以 我试图找到答案 但找不到 拥有类或模块的目的是什么 我读到的所有内容都试图告诉我它是什么 但不是它的用途 为什么我需要制作一个 我读到的所有内容似乎都对阅读教程的人做出了假设 就好像我知道很多一样 模块实际上与仅包含共享