惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Fortinet All Blogs
宝玉的分享
宝玉的分享
酷 壳 – CoolShell
酷 壳 – CoolShell
T
The Exploit Database - CXSecurity.com
Help Net Security
Help Net Security
腾讯CDC
Project Zero
Project Zero
C
CXSECURITY Database RSS Feed - CXSecurity.com
IT之家
IT之家
C
Cyber Attacks, Cyber Crime and Cyber Security
T
Tailwind CSS Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
D
Darknet – Hacking Tools, Hacker News & Cyber Security
L
LINUX DO - 最新话题
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
T
Threatpost
N
News | PayPal Newsroom
C
Cybersecurity and Infrastructure Security Agency CISA
Hacker News - Newest:
Hacker News - Newest: "LLM"
S
SegmentFault 最新的问题
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
P
Proofpoint News Feed
A
Arctic Wolf
B
Blog RSS Feed
Forbes - Security
Forbes - Security
P
Privacy & Cybersecurity Law Blog
Attack and Defense Labs
Attack and Defense Labs
V2EX - 技术
V2EX - 技术
P
Proofpoint News Feed
I
Intezer
Application and Cybersecurity Blog
Application and Cybersecurity Blog
阮一峰的网络日志
阮一峰的网络日志
aimingoo的专栏
aimingoo的专栏
T
Tenable Blog
MyScale Blog
MyScale Blog
U
Unit 42
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
WordPress大学
WordPress大学
W
WeLiveSecurity
D
DataBreaches.Net
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
G
GRAHAM CLULEY
有赞技术团队
有赞技术团队
Martin Fowler
Martin Fowler
罗磊的独立博客
The Last Watchdog
The Last Watchdog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
V
Vulnerabilities – Threatpost
美团技术团队
Microsoft Security Blog
Microsoft Security Blog

博客园 - 水如烟(LzmTW)

.NET的变量在代码集中是不安全的 HOW TO:获取硬盘物理序列号(VB.NET) 一个创建快捷方式类 一个简单的CodeAccessPermission生成器 认识一下Attribute HOW TO:端口打印(比较粗糙) 标记法定义和创建数据库(四) 标记法定义和创建数据库 Sql2005数据类型与Framework类型的对应关系 HOW TO:重启程序(WinForm) HOW TO:设置默认打印机 HOW TO:避免“将COM对象与其基础RCW分开后不能再使用该对象”错误 HOW TO:控制是否允许用户退出ExcelApplication的Workbook 树和自联表(五) 树和自联表(六) 树和自联表(四) 行政区划数据数据库的设计(脚本) 行政区划数据数据库的设计(七) 行政区划数据数据库的设计(六)
树和自联表(一)
水如烟(LzmTW) · 2006-11-07 · via 博客园 - 水如烟(LzmTW)

Author:水如烟 


自联表我们经常用到,它总是跟树联结在一起。
对于它们的处理,.NET没有专门的处理类。
控件类TreeNode,也没有直接跟自联表挂上钩。

所以,我也尝试一下写写这方面的代码。
如我以往所写的一样,仅提供一种方法,至于更好的方法,更好的效率,鉴于自己学识所限,不深究。

通常的,要做成泛型类才能通用。所以,若还是使用.Net FrameWork1.1的话,无法使用下面的类了。

下面是为应用自联表做的树类,只有两个文件:
Node.vb

Namespace LzmTW.uSystem.uCollection<Serializable()> _
    
Public Class Node(Of T)Friend gIsRoot As Boolean = True
        
Friend gParent As Node(Of T)''' <summary>
        ''' 当前节点的父节点
        ''' </summary>
        Public ReadOnly Property Parent() As Node(Of T)
            
Get
                
If Me.IsRoot Then
                    
Return Nothing
                
End If
                
Return gParent
            
End Get
        
End Property''' <summary>
        ''' 树的深度
        ''' </summary>
        Public ReadOnly Property Level() As Integer
            
Get
                
If Me.IsRoot Then
                    
Return 0
                
End If
                
Return Me.Parent.Level + 1
            
End Get
        
End Property''' <summary>
        ''' 当前节点是否是根节点
        ''' </summary>
        Public ReadOnly Property IsRoot() As Boolean
            
Get
                
Return gIsRoot
            
End Get
        
End PropertyPrivate gUserData As Object''' <summary>
        ''' 获取或设置包含树节点有关数据的对象
        ''' </summary>
        Public Property Tag() As Object
            
Get
                
Return gUserData
            
End Get
            
Set(ByVal value As Object)
                gUserData 
= value
            
End Set
        
End PropertyPrivate gItem As T
        
Public Property Item() As T
            
Get
                
Return gItem
            
End Get
            
Set(ByVal value As T)
                gItem 
= value
            
End Set
        
End PropertyFriend gChildren As NodeCollection(Of T)''' <summary>
        ''' 获取第一个子树节点
        ''' </summary>
        Public ReadOnly Property FirstNode() As Node(Of T)
            
Get
                
If gChildren.Count = 0 Then
                    
Return Nothing
                
End If
                
Return gChildren(0)
            
End Get
        
End Property''' <summary>
        ''' 获取最后一个子树节点
        ''' </summary>
        Public ReadOnly Property LastNode() As Node(Of T)
            
Get
                
If gChildren.Count = 0 Then
                    
Return Nothing
                
End If
                
Return gChildren(gChildren.Count - 1)
            
End Get
        
End PropertyPrivate gNodes As NodeCollection(Of T)''' <summary>
        ''' 当前节点的节点集合
        ''' </summary>
        Public ReadOnly Property Nodes() As NodeCollection(Of T)
            
Get
                
Return gNodes
            
End Get
        
End Property''' <summary>
        ''' 当前节点在节点集合中的位置
        ''' </summary>
        Public ReadOnly Property Index() As Integer
            
Get
                
Return GetIndex()
            
End Get
        
End PropertyPrivate Function GetIndex() As Integer
            
If Me.IsRoot Then
                
Return 0
            
End IfReturn Me.Parent.Nodes.IndexOf(Me)
        
End Function''' <summary>
        ''' 获取下一个同级树节点
        ''' </summary>
        Public ReadOnly Property NextNode() As Node(Of T)
            
Get
                
If Me.IsRoot OrElse Me.Index + 1 > Me.Parent.Nodes.Count Then
                    
Return Nothing
                
End IfReturn Me.Parent.Nodes.Item(Me.Index + 1)
            
End Get
        
End Property''' <summary>
        ''' 获取上一个同级树节点
        ''' </summary>
        Public ReadOnly Property PrevNode() As Node(Of T)
            
Get
                
If Me.IsRoot OrElse Me.Index - 1 < 0 Then
                    
Return Nothing
                
End IfReturn Me.Parent.Nodes.Item(Me.Index - 1)
            
End Get
        
End PropertyPrivate Sub Initialzie()
            gNodes 
= New NodeCollection(Of T)(Me)
            gChildren 
= New NodeCollection(Of T)(Me)
        
End SubSub New()
            Initialzie()
        
End SubSub New(ByVal item As T)
            gItem 
= item

            Initialzie()

End SubPublic Function GetNodeCount(ByVal includeSubNodes As BooleanAs Integer
            
Dim mCount As Integer = gChildren.Count
            
If includeSubNodes Then
                
Dim mIndex As Integer = 0
                
Do While (mIndex < gChildren.Count)
                    mCount 
+= gChildren(mIndex).GetNodeCount(True)
                    mIndex 
+= 1
                
Loop
            
End IfReturn mCount
        
End FunctionPublic Sub Remove()
            
If Me.IsRoot Then
                
Throw New Exception("不能移除根节点")
            
End If
            
Me.Parent.Nodes.RemoveAt(Me.Index)
        
End SubPrivate gTable As DataTable
        
Private gByProperty As Boolean''' <summary>
        ''' 将当前节点树转换为表
        ''' </summary>
        ''' <param name="byProperty">取T对象的属性集,否则取T对象的字段集作为表列名</param>
        ''' <param name="includeSubNodes">是否包括子节点的T对象</param>
        Public Function ConvertToDataTable(ByVal byProperty As BooleanByVal includeSubNodes As BooleanAs DataTable
            gTable 
= GetDataTable(byProperty)If gTable.Columns.Count = 0 Then
                
If byProperty Then
                    
Throw New Exception("对象无属性列")
                
Else
                    
Throw New Exception("对象无字段列")
                
End If
            
End If

            gByProperty 

= byPropertyMe.ForEach(New Action(Of T)(AddressOf GetDataTableDatasAction), includeSubNodes)

            gTable.AcceptChanges()

Return gTable
        
End FunctionPrivate Function GetDataTable(ByVal byProperty As BooleanAs DataTable
            
Dim tmpTable As New DataTableIf byProperty Then
                
For Each p As Reflection.PropertyInfo In GetType(T).GetProperties
                    
If p.CanRead Then tmpTable.Columns.Add(p.Name, p.PropertyType)
                
Next
            
Else
                
For Each f As Reflection.FieldInfo In GetType(T).GetFields
                    tmpTable.Columns.Add(f.Name, f.FieldType)
                
Next
            
End IfReturn tmpTable
        
End FunctionPrivate Sub GetDataTableDatasAction(ByVal item As T)
            
Dim tmpRow As DataRow = gTable.NewRowDim mName As StringFor Each c As DataColumn In gTable.Columns
                mName 
= c.ColumnNameIf gByProperty Then
                    tmpRow(mName) 
= GetType(T).GetProperty(mName).GetValue(item, Nothing)
                
Else
                    tmpRow(mName) 
= GetType(T).GetField(mName).GetValue(item)
                
End If
            
Next

            gTable.Rows.Add(tmpRow)

End Sub''' <summary>
        ''' 将当前节点树转换为TreeNode
        ''' </summary>
        ''' <param name="byProperty">取T对象的属性集,否则取T对象的字段集</param>
        ''' <param name="NameOfTreeNodeText">TreeNode的Text值对应的T对象属性名或字段名</param>
        ''' <param name="includeSubNodes">是否包括子节点</param>
        ''' <remarks>TreeNode的Tag存T对象值</remarks>
        Public Function ConvertToTreeNode(ByVal byProperty As BooleanByVal nameOfTreeNodeText As StringByVal includeSubNodes As BooleanAs Windows.Forms.TreeNode
            CheckValid(byProperty, nameOfTreeNodeText)
Dim mTreeNode As System.Windows.Forms.TreeNode = ConvertToTreeNode(Me, byProperty, nameOfTreeNodeText)If includeSubNodes Then AppendTreeNode(mTreeNode, Me, byProperty, nameOfTreeNodeText)Return mTreeNode
        
End FunctionPrivate Shared Sub AppendTreeNode(ByVal treeNode As Windows.Forms.TreeNode, ByVal node As Node(Of T), ByVal byProperty As BooleanByVal nameOfTreeNodeText As String)
            
For Each n As Node(Of T) In node.gChildrenDim mCurrentTreeNode As Windows.Forms.TreeNode = ConvertToTreeNode(n, byProperty, nameOfTreeNodeText)

                treeNode.Nodes.Add(mCurrentTreeNode)

                AppendTreeNode(mCurrentTreeNode, n, byProperty, nameOfTreeNodeText)

NextEnd SubPrivate Shared Function ConvertToTreeNode(ByVal node As Node(Of T), ByVal byProperty As BooleanByVal nameOfTreeNodeText As StringAs System.Windows.Forms.TreeNode
            
Dim mTextValue As StringIf byProperty Then
                mTextValue 
= GetType(T).GetProperty(nameOfTreeNodeText).GetValue(node.Item, Nothing).ToString
            
Else
                mTextValue 
= GetType(T).GetField(nameOfTreeNodeText).GetValue(node.Item).ToString
            
End IfDim mTreeNode As New System.Windows.Forms.TreeNode(mTextValue)
            mTreeNode.Tag 
= node.ItemReturn mTreeNode
        
End FunctionPrivate Sub CheckValid(ByVal byProperty As BooleanByVal nameOfTreeNodeText As String)
            
If byProperty Then
                
Dim mPropertyInfo As System.Reflection.PropertyInfo = GetType(T).GetProperty(nameOfTreeNodeText)
                
If mPropertyInfo Is Nothing Then
                    
Throw New Exception("属性名无效")
                    
If Not mPropertyInfo.CanRead Then
                        
Throw New Exception("属性名不可读")
                    
End If
                
End If
            
Else
                
Dim mFieldInfo As System.Reflection.FieldInfo = GetType(T).GetField(nameOfTreeNodeText)
                
If mFieldInfo Is Nothing Then
                    
Throw New Exception("字段名无效")
                
End If
            
End If
        
End Sub''' <summary>
        ''' 对每个节点执行指定操作
        ''' </summary>
        ''' <param name="action">对指定的对象执行操作的方法</param>
        ''' <param name="includeSubNodes">是否包括子节点</param>
        Public Sub ForEach(ByVal action As Action(Of Node(Of T)), ByVal includeSubNodes As Boolean)
            Node(Of T).ForEach(
Me, action, includeSubNodes)
        
End SubPublic Shared Sub ForEach(ByVal node As Node(Of T), ByVal action As Action(Of Node(Of T)), ByVal includeSubNodes As Boolean)
            
For Each n As Node(Of T) In node.gChildren
                action.Invoke(n)
If includeSubNodes Then ForEach(n, action, True)
            
Next
        
End Sub''' <summary>
        ''' 对每个T对象执行指定操作
        ''' </summary>
        ''' <param name="action">对指定的对象执行操作的方法</param>
        ''' <param name="includeSubNodes">是否包括子节点的T对象</param>
        Public Sub ForEach(ByVal action As Action(Of T), ByVal includeSubNodes As Boolean)
            Node(Of T).ForEach(
Me, action, includeSubNodes)
        
End SubPublic Shared Sub ForEach(ByVal node As Node(Of T), ByVal action As Action(Of T), ByVal includeSubNodes As Boolean)
            
For Each n As Node(Of T) In node.gChildren
                action.Invoke(n.Item)
If includeSubNodes Then ForEach(n, action, True)
            
Next
        
End SubPublic Function Clone() As Node(Of T)
            
Return uSystem.uRuntime.uSerialization.SerializeHelper.Clone(Of Node(Of T))(Me)
        
End FunctionEnd ClassEnd Namespace

NodeCollection.vb

Namespace LzmTW.uSystem.uCollection<Serializable()> _
    
Public Class NodeCollection(Of T)
        
Inherits System.Collections.ObjectModel.Collection(Of Node(Of T))Private gOwner As Node(Of T)Friend Sub New(ByVal node As Node(Of T))
            gOwner 
= node
        
End SubPublic Shadows Function Add(ByVal Value As T) As Node(Of T)
            
Dim mNode As New Node(Of T)(Value)

            Add(mNode)
            gOwner.gChildren.Add(mNode)

Return mNode
        
End FunctionPrivate Shadows Sub Add(ByVal item As Node(Of T))
            
With item
                .gParent 
= gOwner
                .gIsRoot 
= False
            
End WithMyBase.Add(item)
        
End SubPublic Shadows Sub RemoveAt(ByVal index As Integer)
            
If index < 0 OrElse index > Me.Count - 1 Then
                
Throw New Exception("索引无效")
            
End IfDim mNode As Node(Of T) = Me.Item(index)
            Remove(mNode)

            gOwner.gChildren.Remove(mNode)

End SubPublic Shadows Sub Remove(ByVal index As Integer)
            
Me.RemoveAt(index)
        
End SubPrivate Shadows Function Remove(ByVal item As Node(Of T)) As Boolean
            
Return MyBase.Remove(item)
        
End FunctionPublic Shadows Sub Insert(ByVal index As IntegerByVal Value As T)
            
If index < 0 OrElse index > Me.Count - 1 Then
                
Throw New Exception("索引无效")
            
End IfDim mNode As New Node(Of T)(Value)

            Insert(index, mNode)
            gOwner.gChildren.Insert(index, mNode)

End SubPrivate Shadows Sub Insert(ByVal index As IntegerByVal item As Node(Of T))
            
With item
                .gParent 
= gOwner
                .gIsRoot 
= False
            
End WithMyBase.Insert(index, item)
        
End SubPublic Overloads Sub Clear()
            
MyBase.Clear()
            
If gOwner.gChildren.Count > 0 Then gOwner.gChildren.Clear()
        
End SubEnd Class
End Namespace

一个辅助的类,专用于序列化用的。
SerializeHelper.vb

Namespace LzmTW.uSystem.uRuntime.uSerializationPublic Class SerializeHelperPrivate Sub New()
        
End Sub<System.ComponentModel.EditorBrowsable(ComponentModel.EditorBrowsableState.Advanced)> _
        
Public Shared Function ItemToXml(Of T)(ByVal obj As T) As String
            
Dim mResult As String = ""
            
Dim mSerializer As New System.Xml.Serialization.XmlSerializer(GetType(T))
            
Dim mStringWriter As New System.IO.StringWriter
            Using mStringWriter
                mSerializer.Serialize(mStringWriter, obj)
                mResult 
= mStringWriter.ToString
                mStringWriter.Close()
            
End Using
            
Return mResult
        
End Function<System.ComponentModel.EditorBrowsable(ComponentModel.EditorBrowsableState.Advanced)> _
        
Public Shared Function XmlToItem(Of T)(ByVal xml As StringAs T
            
Dim mSerializer As New System.Xml.Serialization.XmlSerializer(GetType(T))
            
Dim mStringReader As New System.IO.StringReader(xml)
            
Return CType(mSerializer.Deserialize(mStringReader), T)
        
End Function<System.ComponentModel.EditorBrowsable(ComponentModel.EditorBrowsableState.Advanced)> _
        
Public Shared Sub ItemToXmlFile(Of T)(ByVal filename As StringByVal obj As T)
            
Dim XmlWriter As New System.IO.StreamWriter(filename, False, System.Text.Encoding.Default)
            Using XmlWriter
                XmlWriter.Write(ItemToXml(obj))
                XmlWriter.Close()
            
End Using
        
End Sub<System.ComponentModel.EditorBrowsable(ComponentModel.EditorBrowsableState.Advanced)> _
        
Public Shared Function XmlFileToItem(Of T)(ByVal filename As StringAs T
            
Dim XmlReader As New System.IO.StreamReader(filename, System.Text.Encoding.Default)
            
Dim mObj As T
            Using XmlReader
                mObj 
= XmlToItem(Of T)(XmlReader.ReadToEnd)
                XmlReader.Close()
            
End Using
            
Return mObj
        
End Function<System.ComponentModel.EditorBrowsable(ComponentModel.EditorBrowsableState.Advanced)> _
        
Public Shared Sub ItemToFormatterFile(Of T)(ByVal filename As StringByVal formatter As System.Runtime.Serialization.IFormatter, ByVal obj As T)
            
Dim mFileStream As System.IO.Stream = System.IO.File.Open(filename, System.IO.FileMode.Create)
            Using mFileStream
                formatter.Serialize(mFileStream, obj)
                mFileStream.Close()
            
End Using
        
End Sub<System.ComponentModel.EditorBrowsable(ComponentModel.EditorBrowsableState.Advanced)> _
        
Public Shared Function FormatterFileToItem(Of T)(ByVal FileName As StringByVal formatter As System.Runtime.Serialization.IFormatter) As T
            
Dim mFileStream As System.IO.Stream = System.IO.File.Open(FileName, System.IO.FileMode.Open)
            
Dim mObj As T
            Using mFileStream
                mObj 
= CType(formatter.Deserialize(mFileStream), T)
                mFileStream.Close()
            
End Using
            
Return mObj
        
End FunctionPublic Shared Function Clone(Of T)(ByVal obj As T) As T
            
Dim tmpT As T
            
Dim mFormatter As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
            
Dim mMemoryStream As New System.IO.MemoryStream
            Using mMemoryStream
                mFormatter.Serialize(mMemoryStream, obj)
                mMemoryStream.Position 
= 0
                tmpT 
= CType(mFormatter.Deserialize(mMemoryStream), T)
                mMemoryStream.Close()
            
End Using
            
Return tmpT
        
End FunctionPublic Shared Sub Save(Of T)(ByVal filename As StringByVal formattype As FormatType, ByVal obj As T)
            
Select Case formattype
                
Case formattype.Binary
                    ItemToFormatterFile(filename, 
New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter, obj)
                
Case formattype.Soap
                    ItemToFormatterFile(filename, 
New System.Runtime.Serialization.Formatters.Soap.SoapFormatter, obj)
                
Case formattype.Xml
                    ItemToXmlFile(filename, obj)
            
End Select
        
End SubPublic Shared Function Load(Of T)(ByVal filename As StringByVal formattype As FormatType) As T
            
Select Case formattype
                
Case formattype.Binary
                    
Return FormatterFileToItem(Of T)(filename, New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter)
                
Case formattype.Soap
                    
Return FormatterFileToItem(Of T)(filename, New System.Runtime.Serialization.Formatters.Soap.SoapFormatter)
                
Case formattype.Xml
                    
Return XmlFileToItem(Of T)(filename)
            
End Select
            
Return Nothing
        
End FunctionEnd ClassPublic Enum FormatType
        Xml
        Binary
        Soap
    
End EnumEnd Namespace

现在可以测试一下。
测试代码:

Public Class Form1Private gNode As New uSystem.uCollection.SinceLink.Node(Of item)(New item("Root"))Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        gNode.Nodes.add(

New item("First"))
        gNode.Nodes.Add(
New item("Second")).Nodes.Add(New item("Four")).Nodes.Add(New item("Five")).Nodes.Add(New item("Seven"))
        gNode.Nodes.Add(
New item("Third"))
        gNode.Nodes.Insert(
1New item("Six"))End SubPrivate Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        
Me.TreeView1.Nodes.Add(gNode.ConvertToTreeNode(True"Name"True))
        
Me.DataGridView1.DataSource = gNode.ConvertToDataTable(TrueTrue)
    
End SubEnd Class<Serializable()> _
Public Class item
    
Private gName As String
    
Private gDeclare As StringPublic Property Name() As String
        
Get
            
Return gName
        
End Get
        
Set(ByVal value As String)
            gName 
= value
        
End Set
    
End PropertyPublic Property [Declare]() As String
        
Get
            
Return gDeclare
        
End Get
        
Set(ByVal value As String)
            gDeclare 
= value
        
End Set
    
End PropertySub New()
    
End SubSub New(ByVal name As String)
        gName 
= name
        gDeclare 
= name
    
End SubSub New(ByVal name As StringByVal [declareAs String)
        gName 
= name
        gDeclare 
= [declare]
    
End SubEnd Class

效果: