0

INI ファイルを管理するために作成した古いクラスを改善しようとしています。クラスには、手順を分離して整理するための 3 つのサブクラス ( FileKeySection) が含まれています (一般的には ini のプロシージャ、キーを管理するプロシージャ/値、およびセクション名を管理するためのプロシージャ)。

さて、私が抱えている問題は、古いクラスではすべてのメンバーが共有されており (props/vars/objects/methods)、明らかにそれが非類似性につながる可能性があることです。メンバーの可視性を完全なものにしたいと思います。私が立ち往生しているところがあります。

クラスの現在の使用法は次のようになります。

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、クラスのメソッドに行き詰まっています私の古いクラスバージョンでやった...FileFilePathExistShared

...では、どうすればこれを改善できますか?

注:他の 2 つのサブクラスには、クラス内だけでなく、名前が付けられたメソッドExistと、" " などの同じ名前の他のメソッドが必要であることに注意してください (それが問題になるかどうかはわかりませんが、さらに多くのことが必要になる可能性がありますレタッチします)。[Get]File

''' <summary>
''' Manages an INI file and it's sections to load/save values.
''' </summary>
Public Class INIFileManager

#Region " Properties "

    ''' <summary>
    ''' Indicates the initialization file location.
    ''' </summary>
    Private Property FilePath As String = String.Empty

    ''' <summary>
    ''' Indicates the initialization file encoding to read/write.
    ''' </summary>
    Private Property TextEncoding As System.Text.Encoding = System.Text.Encoding.Default

#End Region

#Region " Constructors "

    ''' <summary>
    ''' Initializes a new instance of the <see cref="INIFileManager" /> class.
    ''' </summary>
    ''' <param name="IniFile">
    ''' Indicates the initialization file location.
    ''' </param>
    ''' <param name="TextEncoding">Indicates a textencoding to read/write the iniinitialization file.</param>
    Public Sub New(Optional ByVal IniFile As String = Nothing,
                   Optional ByVal TextEncoding As System.Text.Encoding = Nothing)

        If Not String.IsNullOrEmpty(IniFile) Then
            Me.FilePath = IniFile
        Else
            Me.FilePath = IO.Path.Combine(Application.StartupPath,
                                          Process.GetCurrentProcess().ProcessName & ".ini")
        End If

        If Not TextEncoding Is Nothing Then
            Me.TextEncoding = TextEncoding
        End If

    End Sub

#End Region

    ''' <summary>
    ''' Contains a set of procedures to manage the INI file in a general way.
    ''' </summary>
    Private Class [File]

        ''' <summary>
        ''' Checks whether the initialization file exist.
        ''' </summary>
        ''' <returns>True if initialization file exist, otherwise False.</returns>
        Public Function Exist() As Boolean
            Return IO.File.Exists(MyBase.FilePath)
        End Function

        ' More irrelevant methods here that need to access to props and vars of the top-level class...

    End Class

    ' another class here...

    ' and another class here...

End Class
4

1 に答える 1

1

問題の一部は、クラスを通じて階層の詳細を処理するのではなく、明らかにしていることだと思います。もう 1 つの部分は、1980 年代の 16 ビット Windows 技術にしがみついていますが、今日ではより堅牢なメカニズムが存在します。

2 ビットの情報 (キーと値) を管理するための 4 つのクラス (INIManager、ファイル、セクション、キー) があります。INIManager は他のものを「収容」するだけなので、特にファイル レベルの操作があまりないため、ファイルと組み合わせることができます。[Sections] も必要ないでしょう。これらは存在するだけなので、次のような同様のアイテムについて繰り返し属性を保存できます。

 [MainDB]
 Path =  
 File =  
 Foo =

 [Report DB] 
 Path =  
 File =  
 Foo =

これらは、FILE1、FILE2... などの文字列のコレクションをループして、ループ内の複数のセクションを読み取ることができる方法で、INItialization 値を提供することを目的としていました。一連の設定を単純にする場合は、単一の [Default] セクションを使用して、クラスとその使用を簡素化します。次に、IniManager と Keys に進みます。基礎となる階層を意図的に公開することは、使いやすさには役立ちません。

INIManagerしたがって、必要なことを行うには、セクション関連のものを公開するSECTIONS プロパティが必要です。それをサポートするには、INISectionクラス (主にセクションのメソッド) とINISectionSコレクション クラスが必要です。(いくつかのコメントは、すべてのセクションとそのすべてのキーを常にロードして、それらを削除できるようにしたいという推測につながります)。

のようなものが本当に必要な場合は、クラスSections().Keys().Methodを追加する必要があります。これにより、2 つの情報を管理するために総計で 5 つのクラスが作成されます。もちろん、半分のコードと 1 つのクラスで実行できます。余分な綿毛のほとんどは、あなたが言及した方法で内部の仕組みを公開するためにあります. また、公開したくないことを明らかにしないように、Public vs Friend を楽しむこともできます。KeyKeys collection classIniSection

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 つのクラスは正気ではありません)。セッターが一致するように変更するには、Keys アクセサーを削除して and を追加し、.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()
于 2014-06-22T03:45:25.140 に答える