如何正确地构造这个类的可见性? [英] How to properly structurate the visibility of this Class?

查看:242
本文介绍了如何正确地构造这个类的可见性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图改进一个我写的管理一个INI文件的类,该类包含3个子类( File Key )来分隔和组织过程(一般为ini的procs,用于管理键/值的procs,

I'm trying to improve an old Class that I've wrote to manage an INI file, the Class contains 3 sub-Classes (File, Key, Section) to separate and organize the procedures (procs for the ini in general, procs for manage the keys/values, and procs for manage the section names).

好吧,我的问题是在旧类中所有的成员被共享(props / vars / objects /方法)这可能会导致消退,那么我想尝试完善成员的可见性,并且有我被困在哪里。

Well, the problem I have is that in the old class all the members were shared (props/vars/objects/methods) and obviouslly that could result in a disimbiguation, then I would like to try to perfectionate the visibility of the members, and there is where I'm stuck.

当前使用的类如下:

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

我想使用的应该是这样:

And the usage that I would like should be like this:

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 code> File class'因为我不能访问位于顶级类的 FilePath 变量,因为我没有设置这个变量和 Exist 方法都像 Shared ,就像我在旧的Class版本...

Below is the relevant code for this example, I'm stuck on the Exist method of the File class 'cause I cannot access to the FilePath variable which is at the top-level class since I don't set that variable and the Exist method both as Shared like I did on my old Class version...

...那么我该如何改进呢?

...So how I can improve this?

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

NOTE: Please keep in mynd that the other 2 sub-Classes should have a method named Exist and other methods with equal names such as "[Get]", not only in the File Class (I don't know if that could be a problem that could need more retouches).

''' <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


推荐答案

我认为问题的一部分是,你是透露,而不是处理太多的细节层次结构通过类。

I think part of the problem is that you are revealing rather than handling too much detail of the hierarchy thru the class. The other part is clinging to 1980's 16bit Windows tech when there are much more robust mechanisms around today.

你有4个类(INIManager,File,Section,Key)来管理2位信息(密钥和值)。因为INIManager只是安装其他人,他可以结合文件 - 特别是因为没有许多文件级操作。你可能甚至不需要[部分]。那些只存在,所以你可以存储类似项目的重复属性,如:

You have 4 classes (INIManager, File, Section, Key) to manage 2 bits of information (Key and Value). Since INIManager is just to "house" the others, he can be combined with File - especially since there arent many file level operations. You likely do not even need [Sections]. Those only existed so you could store repeated attributes about similar items like:

 [MainDB]
 Path =  
 File =  
 Foo =

 [Report DB] 
 Path =  
 File =  
 Foo =

这些是为了提供INItialization值,你可以循环通过一个字符串,如FILE1,FILE2 ...的集合,并读取多个部分循环。对于一组简单的设置,只需使用一个[Default]节来简化类及其使用。然后,你只是下来到IniManager和键。

These were intended to provide INItialization values in a way where you could loop thru a collection of strings like FILE1, FILE2... and read multiple sections in a loop. For a simple set of settings, just use a single [Default] section to simplify the class and its use. Then, you are just down to IniManager and Keys. Purposely exposing the underlying hierarchy doesnt lend itself to usability, IMO.

因此,为了做你想要的,你需要一个SECTIONS属性在 INIManager code>这暴露了节相关的东西。为了支持这一点,你需要一个 INISection 类(主要是Sections的方法)和一个 INISectionS 集合类。 (有些评论让我推测,你想加载所有的部分所有的时间和所有的键,所以他们可以删除等)。

So to do what you want, you need a SECTIONS property on INIManager which exposes the section related stuff. To support that, you need a INISection class (mainly the methods for Sections) AND a INISectionS collection Class. (Some Comments lead me to surmise that you want to load all the sections all the time and all their keys so they can be deleted etc).

如果你真的想要 Sections()。Keys()。方法,您必须添加类和键集合类 IniSection 。这将带来总共5个类管理2件信息。当然,它可以用一半的代码和1类。大多数额外的绒毛是以暴露内部工作方式你提到的方式。你也可以用公共vs朋友的乐趣,避免暴露一些你不想要的东西。

If you really want something like Sections().Keys().Method, you will have to add a Key class and Keys collection class on IniSection. Which would bring the grand total to 5 classes to manage 2 pieces of information. Of course, it can be done with half the code and 1 class. Most of the extra fluff is there to expose the inner workings the way you mentioned. You'll also have fun with Public vs Friend to keep from revealing some things you dont want to.

我没有什么在代码中做PInvokes;这个问题涉及类的建设,而不是INI的管理。大多数方法都是空的,只存在于查看它们如何为穷人用户。

I dont have anything in the code to do the PInvokes; The question deals with class construction not INI management. Most methods are empty and exist just to see how they end up for the poor user.

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

$ b b




示例语法:


Sample syntax:

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集合类(5个类的2位信息是疯狂的)。要改变它以使setter匹配,删除Keys存取器并添加 .ReadKey() SetKey 语法和保持密钥集合内部。你最终会得到:

These dont match syntactically because I didnt create a Key class and Keys collection class (5 classes for 2 bits of information is insane). To change it so the setter matches, remove the Keys accessor and add a .ReadKey() and SetKey so it matches syntactically and keep the keys collection internal. You'll end up with:

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()

这篇关于如何正确地构造这个类的可见性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆