我可以从Internet上了解到很多知识,即VB.Net模块与c#.Net静态类是同一件事。我还可以阅读到类似于Static Class
的东西是一个看起来像这样的类:
'NotInheritable so that no other class can be derived from it
Public NotInheritable Class MyAlmostStaticClass
'Private Creator so that it cannot be instantiated
Private Sub New()
End Sub
'Shared Members
Public Shared Function MyStaticFunction() as String
Return "Something"
End Function
End Class
我发现这段代码很容易起草和阅读。像这样使用Module
,我会感到更加自在:
Public Module MyEquivalentStaticClass
Public Function MyStaticFunction() as String
Return "Something"
End Function
End Module
但是,对于Module
,您将失去Namespace
层次结构的一个级别,并且以下3条语句相等:
'Call through the Class Name is compulsory
Dim MyVar as String = Global.MyProject.MyAlmostStaticClass.MyStaticFunction()
'Call through the Module Name is OPTIONNAL
Dim MyVar as String = Global.MyProject.MyEquivalentStaticClass.MyStaticFunction()
Dim MyVar as String = Global.MyProject.MyStaticFunction()
我觉得这很不方便,这会污染Intelisense,或者迫使我创建Namespace
的附加级别,这意味着需要更多Module
声明,即更多Intelisense污染。
如果您要避免使用繁重的SharedMembers-NotInheritable-PrivateNew Class
声明,是否有解决方法?或者要为此付出代价吗?
其他参考文献包括Cody Gray的精彩文章:https://stackoverflow.com/a/39256196/10794555
答案 0 :(得分:7)
不,在VB.NET中没有与C#静态类完全相同的东西。如果VB能够将Shared
修饰符添加到类声明中,就像这样:
Public Shared Class Test ' This won't work, so don't try it
' Compiler only allows shared members in here
End Class
但是,不幸的是,事实并非如此。如果这样做,编译器会给您以下错误:
不能将类声明为“共享”
这为我们提供了您列出的两个选项:
Shared
个成员的非实例化类(在编译器不强制执行该规则的情况下),或者Module
,它可以使所有内容Shared
,即使您没有通过Shared
修饰符明确地这么说正如您所说,很多人不喜欢丢失类名,因为它是一种额外的命名空间层,因此他们更喜欢Class
仅具有Shared
个成员的情况。 Module
。但是,这是一个优先事项。
值得注意的是,虽然您不必 在调用其成员的任何地方指定模块名称,但是您可以随时这样做:
MyModule.MyMethod()
尽管您雄辩地称其为“ SharedMembers-NotInheritable-PrivateNew类”,但它与静态类最接近,但在功能上却是等效的。如果使用反射,则会看到类型的属性不相同。例如,在VB中:
Module MyModule
Public Sub Main()
Dim t As Type = GetType(MyClass)
End Sub
End Module
Public NotInheritable Class MyClass
Private Sub New()
End Sub
Public Shared Sub MyMethod()
End Sub
End Class
如果您查看t.Attributes
,就会发现它等于Public Or Sealed
。因此MyClass
类型既是密封的(NotInheritable
)又是公共的。但是,如果您在C#中执行此操作:
class Program
{
static void Main(string[] args)
{
Type t = typeof(Test);
}
}
public static class MyClass
{
public static void MyMethod()
{ }
}
然后您再次检查t.Attributes
,这次的值为Public | Abstract | Sealed | BeforeFieldInit
。不一样由于您无法同时在VB中将一个类声明为NotInheritable
和MustInherit
,因此您没有机会完全复制该内容。因此,尽管它们或多或少是等效的,但类型的属性却不同。现在,只是为了好玩,让我们尝试一下:
Module MyModule
Public Sub Main()
Dim t As Type = GetType(MyModule)
End Sub
End Module
现在,模块的t.Attributes
是Sealed
。而已。仅Sealed
。所以也不一样。在VB中获得真正的静态类的唯一方法(意味着,通过反射检查类型具有相同的属性)是将其写入C#类库,然后在VB中引用该库。
答案 1 :(得分:0)
仅使用模块,我会感到更加舒适
因此,请使用模块。
Module SomeModuleNameHere
Public Function MyStaticFunction() As String
Return "Something"
End Function
End Module
您根本不需要Global.MyProject
或模块名称,只需在任何地方直接调用函数即可:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim x As String = MyStaticFunction()
Debug.Print(x)
End Sub
但是,如果需要,您可以使用模块名称,而无需使用Global部分:
Dim x As String = SomeModuleNameHere.MyStaticFunctions
但是,唯一必须使用模块名称的时间是,如果在不同模块中有两个具有完全相同名称的函数。然后,您必须使用它们的完全限定名称来区分它们。
答案 2 :(得分:0)
在到目前为止进行的所有讨论中,多亏了史蒂芬·多格特(Steven Doggart)的投入和TnTinMn的评论,我得出了以下广泛的反馈意见和指南。
Static
关键字用于C#.Net,而不是VB.Net。 VB等效为Shared
,但VB不允许使用Shared
类(仅成员)。下面介绍的准则是在VB中接近C#Static Class
的尝试。
由于此类VB类不能为Shared
,因此将其描述为“静态”。Namespace
(始终称为“ MySpace”),以使这些示例位于Namespace
层中不会造成混淆:都在MySpace层中。 MySpace层不是强制性的,可以根据需要将其剥离。使用Module
,但不要依赖Module
名称作为Namespace
层。而是将路径完全集成到Namespace
声明中,例如:
Namespace MySpace.MyStaticClass
Module _Module
Function MyStaticFunction()
Return "Something"
End Function
End Module
End Namespace
然后应通过Global.MyProject.MySpace.MyStaticClass.MyStaticFunction()
Namespace
路径的一部分可以剥离,具体取决于位置
您位于。通常,MySpace.MyStaticClass.MyStaticFunction()
就足够了。_Module
作为Module
名称将
降低Intelisense下拉菜单中模块的外观,以及
还要明确地说这是一个模块。在这种情况下,上面提到的一般样式将产生:
Namespace MySpace.MyStaticClass
Module _Module
Function MyStaticFunction()
Return "Something"
End Function
End Module
End Namespace
Namespace MySpace.MyStaticClass.MyStaticSubClass1
Module _Module
Function MyStaticFunction()
Return "Something"
End Function
End Module
End Namespace
Namespace MySpace.MyStaticClass.MyStaticSubClass2
Module _Module
Function MyStaticFunction()
Return "Something"
End Function
End Module
End Namespace
在每个“封装的”“静态类”需要一个单独的命名空间声明的意义上,这可能很快变得很沉重。缺点包括:
Namespace
体系结构/树状结构将不太直观:在上述示例中,这意味着检查所有包含“ MyStaticClass”的声明。Namespace
声明,因此起草繁重。Namespace
将需要对多个Namespace
声明进行更改:在上面的示例中,这意味着将'MyStaticClass'更改3次。 (右键单击/重命名是您最好的朋友)一种替代方法是使用具有共享成员的封装类:
Namespace MySpace
Public Class MyStaticClass
Public Function MyStaticFunction()
Return "Something"
End Function
Public Class MyStaticSubClass1
Public Shared Function MyStaticFunction()
Return "Something"
End Function
End Class
Public Class MyStaticSubClass2
Public Shared Function MyStaticFunction()
Return "Something"
End Function
End Class
End Class
End Namespace
import
命名空间,但不使用import
类,因此封装类通常会“强制”完全依赖封装的类之间的路径:MyStaticClass.MyStaticSubClass1
。您不能将Module
封装在另一个Module
中,但始终可以使用Module
的混合物来封装一个或多个类和子类。下面的示例实现了与上面的示例类似的功能:
Namespace MyStaticClass
Public Module _Module
Public Function MyStaticFunction()
Return "Something"
End Function
Public Class MyStaticSubClass1
Public Shared Function MyStaticFunction()
Return "Something"
End Function
End Class
Public Class MyStaticSubClass2
Public Shared Function MyStaticFunction()
Return "Something"
End Function
End Class
End Module
End Namespace
如果最终产品是DLL,并且打算与更多的读者共享,则建议在“静态”类别周围放置安全网。尽管这不会影响编译器查看代码的方式,但可以防止其他人犯错误,或者至少可以快速触发错误并迅速进行调试:
Class
NotInheritable
,以便没有人尝试从静态Class
派生Class
:通常派生这样的类是没用的。New
创建者语句Private
,以便没有人尝试实例化Class
:静态Class
不应包含任何非静态({{1 }})成员;如果是这样,那是一个错字,尝试实例化非共享成员可能会带来问题。下面的示例实现了与上面的示例类似的功能:
Shared
只能在Namespace MySpace
Public NotInheritable Class MyStaticClass
Private Sub New()
End Sub
Public Function MyStaticFunction()
Return "Something"
End Function
Public NotInheritable Class MyStaticSubClass1
Private Sub New()
End Sub
Public Shared Function MyStaticFunction()
Return "Something"
End Function
End Class
Public NotInheritable Class MyStaticSubClass2
Private Sub New()
End Sub
Public Shared Function MyStaticFunction()
Return "Something"
End Function
End Class
End Class
End Namespace
块中声明<System.Runtime.CompilerServices.Extension()>
。但是Module
名称对扩展名没有影响,因此,此主题在这里并没有实际意义。
请参阅Peter Macej提供的链接:https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/procedures/extension-methods