0

我的每个 VB.NET 项目都需要一组特定的自定义模块。例如:

modLog modGUID modControls modRegistry

在其中一些模块中,我有一些对其他模块的引用。

例如,子 modLog.WriteLog 如下所示:

Public Sub WriteLog(Byval uText As String)

 If globalclassOEM.IsOEMVersion Then
     sPath = (some custom path)
 Else
     sPath = (some default path)
 End  if

 'Write log text to file

End Sub

这真的很愚蠢,因为有时我必须将很多模块和类添加到一个小项目中,只是为了解决上述的一些依赖关系并能够使用一些我真正需要的模块。

VB.NET 中是否有避免这种情况的最佳策略?

4

3 回答 3

3

避免此类问题的最佳方法是避免该问题;) 意味着:图书馆应该完全按照他们的意图去做,而不是在后台做一些“额外的工作”。在您的示例中:为什么 WriteLog 函数需要确定路径以及调用者为什么不定义它并将其传递给日志记录函数/类?

如果您仍然希望或需要以这种方式拥有功能,您可以通过定义接口来规避问题,然后将所有接口放入单个库中,而不是实现它们的类。这仍然需要加载带有接口定义的文件,但当然您不需要加载任何实现它的类。

您还可以使用某种插件系统,并且在创建日志记录类(在此示例中)时,它可能会尝试动态加载所需的程序集。如果它们不退出,则该类将没有它们,否则它可以假装使用它们。不过(恕我直言)并没有让程序员的生活更轻松。

“最好”的方式(再次恕我直言)将是第一个建议。没有引用其他库的“低级”库。其他一切最有可能被认为是设计缺陷而不是“解决方案”。

于 2012-12-11T08:08:43.330 回答
1

我没有介绍 VB.net 中的全部引用,但是,您是否可以创建一个包含所有基本模块的 .dll。这意味着您可以引用这个 .dll 来节省您的时间。对于您引用其他模块的情有可原的情况,您可以手动编写该模块。

于 2012-12-11T07:56:35.723 回答
1

正如其他人所暗示的那样,您永远不想在多个项目中直接包含相同的代码文件。这几乎不是一个好主意,它总是会导致代码混乱。如果您有想要在两个不同项目之间共享的公共代码,那么您需要创建第三个项目(类库),其中将包含公共代码,然后其他两个项目将只引用类库。如果您可以在同一个解决方案中拥有所有三个项目,那么您可以使用项目引用,这是最好的。但是,如果您不能这样做,您仍然可以直接引用该类库项目输出的 DLL 文件。

其次,如果你真的想避免意大利面条式代码,你应该认真研究依赖注入(DI)。我和其他人提出这个建议的原因是,即使您将公共代码移动到类库中以便可以由多个项目共享,您仍然会遇到您的类库充当“黑盒”的问题“它神奇地为你找出一切,并在每种情况下采取适当的行动。从表面上看,这听起来像是开发人员应该努力争取的一件好事,但实际上,从长远来看,这会导致糟糕的代码。

例如,当您想在 100 个不同的项目中使用相同的日志记录类库并且它们都需要以稍微不同的方式进行日志记录时会发生什么。现在,您的类库必须神奇地检测所有这些不同的情况并处理它们。例如,某些项目可能需要将日志保存到不同的文件名。有些可能需要将日志存储到 Windows 事件日志或数据库中。有些人可能需要在记录错误时自动通过电子邮件发送通知。等等你可以想象,随着项目的增加和需求的增长,日志类库将需要变得越来越复杂和混乱,这将不可避免地导致更多的错误。

另一方面,DI 解决了所有这些问题,如果您坚持该方法,它将从本质上迫使您编写可重用的代码。简单来说,它只是意味着一个类的所有依赖项都应该被注入(通过参数传递)到它里面。换句话说,如果 Logger 类需要事件日志或数据库连接,它不应该自己创建或伸出手来查找这些东西。相反,它应该只要求将这些依赖项传递给它(通常在构造函数中)。您使用 DI 的示例可能如下所示:

Public Interface ILogFilePathFinder
    Function GetPath() As String
End Interface

Public Class LogFilePathFinder
    Implements ILogFilePathFinder

    Public Sub New(isOemVersion As Boolean)
        _isOemVersion = isOemVersion
    End Sub

    Private _isOemVersion As Boolean

    Function GetPath() As String Implements ILogFilePathFinder.GetPath
        If _isOemVersion Then
            Return "C:\TestOem.log"
        Else
            Return "C:\Test.log"
        End If
    End Function
End Class

Public Interface ILogger
    Sub WriteLog(ByVal text As String)
End Interface

Public Class FileLogger
    Implements ILogger

    Public Sub New(pathFinder As ILogFilePathFinder)
        _pathFinder = pathFinder
    End Sub

    _pathFinder As ILogFilePathFinder

    Public Sub WriteLog(text As String) Implements ILogger.WriteLog
        Dim path As String = _pathFinder.GetPath()
        ' Write text to file ...
    End Sub
End Class

如您所见,它需要一些额外的工作,但是当您像这样设计代码时,您将永远不会后悔。您会注意到记录器类请求路径查找器作为依赖项。路径查找器反过来请求 OEM 设置作为依赖项。因此,要使用它,您需要执行以下操作:

Dim pathFinder As ILogFilePathFinder = New FileLogPathFinder(_OemSettings.IsOemVersion)  ' Note, don't use a global to store the settings, always ask for them to be injected
Dim logger As ILogger = New FileLogger(pathFinder)
logger.WriteLog("test")

现在,您可以在任何情况下轻松重用所有这些代码。例如,如果您有不同的项目需要使用不同的日志文件路径,他们仍然可以使用 commonFileLogger类,他们只需要各自实现自己的版本,ILogFilePathFinder然后将自定义路径查找器注入 common FileLogger. 希望你能看到这样做是如何非常有用和灵活的。

于 2012-12-11T10:03:41.700 回答