我的每个VB.NET项目都需要一组自定义模块。 例如:
modLog modGUID modControls modRegistry
在某些模块中,我有一些对其他模块的引用。
例如sub 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中有没有最好的策略来避免这种情况?
答案 0 :(得分:3)
避免此类问题的最佳方法是避免这个问题;)意味着:图书馆应该完全按照他们的意图去做,而不是在backgorund做一些“额外的工作”。在您的示例中:为什么WriteLog函数需要确定路径以及调用者为什么不定义它并将其传递给日志记录函数/类?
如果您仍然希望或需要以这种方式拥有这些功能,您可以通过定义接口然后将所有接口放入单个库来避免问题,但不是实现它们的类。这仍然需要使用接口定义加载文件,但当然您不需要加载任何实现它的类。
您也可以使用某种插件系统,当您创建日志类(在此示例中)时,它可能会尝试动态加载所需的程序集。如果它们没有退出,那么该类将没有它们,否则它可以作为假装使用它们。然而,(imho)并不能让程序员的生活更轻松。
“最佳”方式(imho再次)将是第一个建议。没有引用其他库的“低级”库。其他一切最有可能被认为是设计缺陷,而不是“解决方案”。
答案 1 :(得分:1)
我没有在VB.net中覆盖整个引用堆,但是,您是否可以使用所有基本模块创建.dll。这意味着你可以参考这个.dll,节省你的时间。对于你有引用其他模块的情有可原的情况,你可以手动编写该模块。
答案 2 :(得分: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")
现在,您可以在任何情况下轻松地重用所有这些代码。例如,如果您有不同的项目需要使用不同的日志文件路径,他们仍然可以使用公共FileLogger
类,他们只需要实现自己的ILogFilePathFinder
版本,然后注入自定义路径查找器进入公共FileLogger
。希望你看到这样做的方式非常有用和灵活。