如何正确构建此类的可见性?

时间:2014-06-21 15:21:53

标签: .net vb.net class class-structure

我试图改进我为管理INI文件而编写的旧类,该类包含3个子类(FileKey,{{1分离和组织过程(一般来说是proc的过程,用于管理键/值的过程,以及用于管理段名的过程)。

嗯,我遇到的问题是,在旧班级中所有成员都被共享(道具/变量/对象/方法)并且明显可能导致分离,然后我想尝试完善其可见性成员,还有我被困的地方。

Class的当前用法是这样的:

Section

我想要的用法应该是这样的:

INIFileManager.FilePath = "ini filepath"
dim iniexist as boolean = INIFileManager.File.Exist

以下是此示例的相关代码,我被卡在dim ini as new inifilemanager("ini filepath", textencoding) dim iniexist as boolean = ini.file.exist dim another_ini as new inifilemanager("another ini filepath without any kind of conflict with the first instance", textencoding) dim another_iniexist as boolean = another_ini.file.exist 类的Exist方法上,因为我无法访问File变量这是在顶级课程,因为我没有设置该变量,而FilePath方法都像我Exist那样在我的旧班级版本上...

......那我怎么能改善这个呢?

注意:请保留其他2个子类应该有一个名为Shared的方法和其他名称相同的方法,例如" Exist ",不仅在[Get]班级(我不知道这可能是一个可能需要更多修饰的问题)。

File

1 个答案:

答案 0 :(得分:1)

我认为问题的一部分是你透露而不是通过类处理层次结构的太多细节。另一部分是坚持1980年代的16位Windows技术,当时有更强大的机制。

您有4个类(INIManager,File,Section,Key)来管理2位信息(Key和Value)。由于INIManager只是“容纳”其他人,因此他可以与File结合使用 - 特别是因为没有很多文件级操作。你可能甚至不需要[章节]。那些只存在,所以你可以存储类似项目的重复属性,如:

 [MainDB]
 Path =  
 File =  
 Foo =

 [Report DB] 
 Path =  
 File =  
 Foo =

这些旨在以一种方式提供INItialization值,您可以通过一系列字符串循环,如FILE1,FILE2 ......并在循环中读取多个部分。对于一组简单的设置,只需使用一个[Default]部分来简化类及其使用。然后,您只需要使用IniManager和Keys。有目的地暴露底层层次结构并不适用于可用性,IMO。

为了做你想做的事,你需要INIManager上的SECTIONS属性,它暴露了与部分相关的东西。为了支持这一点,您需要INISection类(主要是章节的方法)和INISectionS集合类。 (有些评论让我猜测你想要一直加载所有部分及所有密钥,以便删除它们等等。)

如果您真的想要Sections().Keys().Method之类的内容,则必须在Key上添加Keys collection class课程和IniSection。这将使总计达到5个班级来管理2个信息。当然,它可以用一半的代码和一个类来完成。大多数额外的绒毛都是以你提到的方式暴露内部工作。你也可以和Public vs Friend一起玩,以防止暴露你不想要的东西。

我在代码中没有任何东西来做PInvokes;这个问题涉及阶级建设而不是INI管理。大多数方法都是空的,只是为了看看它们如何最终为穷人用户而存在。


Public Class INIManager

    ' all the gory PInvokes go here

    Friend cfgFile As String
    Public Property INIExists As Boolean

    ' this is the bit you seemed to be missing
    ' A Collection property exposed at the IniMgr level
    ' containing a collection of Sections.  Like matryoshka dolls, inside
    ' each is a collection of Keys and Values
    Public Property Sections As IniSections

    ' no reason for INI mgr to even exist without a file
    Public Sub New(iniFile As String)
        cfgFile = iniFile
        _INIExists = System.IO.File.Exists(cfgFile)

        _Sections = New IniSections(cfgFile)
    End Sub

    ' only worthwhile thing I can think of that a "File"
    ' class would ever do.  
    Public Sub RemoveFile()

    End Sub

    Public Sub Save()
         ' i think you need to delete the file first so any
        ' deleted sections disappear. of course sections the code
        ' does ask for doesnt do any harm either

        ' iterate IniSections to call a Save there,
        ' which iterates the keys one by one to save them
        Sections.Save(cfgFile)
    End Sub

    ' ****** INISections Class Collection
    Public Class IniSections
        'Inherits Collection(Of IniSection)
        Private Items As Collection(Of IniSection)

        Private cfgFile As String

        Friend Sub New(file As String)
            cfgFile = file

            ' I am assuming from some comments that you are probably
            ' loading the entire file to manage it.  for that:

            If System.IO.File.Exists(cfgFile) Then
                ' load from GetPrivateProfileSectionNames into the collection
                ' mybase.Items.Add(section_name)...then

                For Each s As IniSection In Items
                    s.LoadKeyValues(cfgFile)
                Next

            End If

        End Sub

        ' FRIEND!
        Friend Sub Save(cfgfile As String)
            For Each s As IniSection In Items
                ' instruct each section to write the kvps
                s.Save(cfgfile)
            Next
        End Sub

        ' I dont know why an empty accessor is showing up in Intellisense
        Default Public ReadOnly Property Item(name As String) As IniSection
            Get
                If IndexOfSection(name) = -1 Then
                    Items.Add(New IniSection(name))
                End If
                Return Items(IndexOfSection(name))
            End Get

        End Property

        ' add a section
        Public Function Add(name As String) As IniSection
            Dim sec As New IniSection(name)
            Items.Add(sec)
            Return sec
        End Function

        ' remove a section
        Public Sub Remove(name As String)

            Items.RemoveAt(IndexOfSection(name))

    ' the only real way to remove a section is to rewrite the file! 
    ' so to support this method we have to load all sections and all keys
    ' all the time even if we dont need them so that we can write the
    ' out the whole file omitting removed keys and sections.
    '
    ' Seriously sir, this kind of junk went to the dustbin with Rubik's Cubes

        End Sub

        Public Function Exists(secName As String)
            Return IndexOfSection(secName) <> -1
        End Function

        Private Function IndexOfSection(name As String) As Integer
            For n As Integer = 0 To Items.Count - 1
                ' s/b ToLowerInvariant - that makes the screen scroll
                If Items(n).SectionName.ToLower = name.ToLower Then
                    Return n
                End If
            Next
            Return -1
        End Function

    End Class
End Class

' ************** INISection item class
Public Class IniSection
    ' mostly methods go here for sections,
    ' but is the "host" for the keys collections

    Private myKeys As Dictionary(Of String, String)

    ' for a .Keys collection (WHY would the calling code WANT to
    ' mess with the whole collection???), change to add a Key Class
    ' and Keys Collection

    ' interface for Keys
    Public Property Keys(name As String) As String
        Get
            If myKeys.ContainsKey(name) Then
                Return myKeys(name)
            Else
                Return ""
            End If
        End Get
        Set(value As String)
            If myKeys.ContainsKey(value) Then
                myKeys(value) = value
            Else
                myKeys.Add(value, value)
            End If
        End Set
    End Property

    Public Property SectionName As String

    Public Sub New(name As String)
        SectionName = name
        myKeys = New Dictionary(Of String, String)
    End Sub

    Public Sub RemoveKey(name As String)
        If myKeys.ContainsKey(name) Then
            myKeys.Remove(name)
        End If
    End Sub

    Friend Sub Save(inifile As String)
        ' iterate keys writitng the kvps to the ini

    End Sub

    ' note FRIEND called by the INISection class not the user
    Friend Function LoadKeyValues(inifile As String) As Integer
        '  presumably call GetPrivateProfileSection  
        '   for this SectionName and parse it to 
        ' get the current key=value pairs into myKeys
        Return myKeys.Count
    End Function

End Class

示例语法:

ini = New INIManager("C:\Temp\Ziggy.INI")
Dim foo As String = ini.Sections("foo").Keys("bar")

ini.Sections("ziggy").Keys("foo") = "zoey"
ini.Sections("ziggy").RemoveKey("zacky")

这些在语法上不匹配,因为我没有创建Key类和Keys集合类(2个信息的5个类是疯狂的)。要更改它以便setter匹配,请删除Keys访问者并添加.ReadKey()SetKey,以使其在语法上匹配并将密钥集合保持在内部。你最终会得到:

ini.Sections("ziggy").RemoveKey("zacky")
ini.Sections("ziggy").ReadKey("ziggy")
ini.Sections("ziggy").SetKey(keyName, "zoey")

至少它们符合语法

ini.Sections.Add("ziggy")
ini.Sections.Remove("zoey")
If ini.Sections.Exists("zacky") Then
    Console.Beep()
End If

' causes a cascade from INI -> Sections -> keys to save
ini.Save()