Close

C#: Convert a tree node and sub nodes to text

Screen Shot 2013-02-20 at 10.45.56 PM

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TreeToText
{
    class TreeToText
    {
        const string LineMid = "├─";
        const string LineLast = "└─";
        const string Line = "│  ";
        const string Space = "    ";

        /// <summary>
        /// Convert a tree node to text
        /// </summary>
        /// <param name="node">Root node to convert</param>
        /// <returns>Text</returns>
        public static string Tree2Text(TreeNode node)
        {
            if (node == null) return null;
            StringBuilder builder = new StringBuilder();
            builder.AppendLine(TreeNodeText(node));
            Tree2Text(builder, node, "");
            return builder.ToString();
        }

        static string TreeNodeText(TreeNode node)
        {
            return node.Text;
        }

        static void Tree2Text(StringBuilder builder, TreeNode parent, string prefix)
        {
            int nodesCount = parent.Nodes.Count;
            if (nodesCount == 0) return;
            int nodeMaxIndex = nodesCount - 1;
            for (int i = 0; i < nodesCount; i++)
            {
                builder.Append(prefix);
                TreeNode node = parent.Nodes[i];
                if (i != nodeMaxIndex)
                {
                    builder.Append(LineMid);
                    builder.AppendLine(TreeNodeText(node));
                    Tree2Text(builder, node, prefix + Line);
                }
                else
                {
                    builder.Append(LineLast);
                    builder.AppendLine(TreeNodeText(node));
                    Tree2Text(builder, node, prefix + Space);
                }
            }
        }
    }
}

中国IP地址段抽取工具

本工具可以将所有中国的IP v4地址段抽取出来,并按照用户给定的格式保存。
通常可以用于制作特定的路由表。

IP信息来源:每次运行时自动获取自APNIC。
运行需要:dotnet Framework 4.0

运行前,请用文本编辑器打开CNRouteExtractor.exe.config,按照注释修改其中的Format字符串。
运行时的格式:CNRouteExtractor filename
将生成filename作为目标输出文件。如不指定filename则不输出(仅测试下载与抽取)。

下载地址

Recursive Enumerator

using System;
using System.Collections.Generic;

namespace SecretNest.RecursiveEnumerator
{
    /// <summary>
    /// Get the enumerator for querying the parents of specified item.
    /// </summary>
    /// <typeparam name="T">Item type</typeparam>
    /// <param name="current">Item for querying parents</param>
    /// <returns>Enumerator of parents querying</returns>
    public delegate IEnumerator<T> GetParentsEnumerator<T>(T current);

    /// <summary>
    /// Enumerator for querying parents
    /// </summary>
    /// <typeparam name="T">Item type</typeparam>
    public class Enumerator<T> : IEnumerator<T>
    {
        T current, initial;

        Queue<T> notQueried = new Queue<T>();

        HashSet<T> queried = new HashSet<T>(); //for avoiding duplicated query
        Queue<T> rollbackHistory = new Queue<T>(); //for soft reset
        Queue<T> history = new Queue<T>(); //for soft reset
        IEnumerator<T> activeQuery;

        /// <summary>
        /// Callback for getting the enumerator, which is used for querying the parents of specified item.
        /// </summary>
        public GetParentsEnumerator<T> GetParentsEnumeratorCallback { get; set; }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="initial">Initial item</param>
        public Enumerator(T initial)
        {
            notQueried.Enqueue(initial);
            this.initial = initial;
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="initial">Initial item</param>
        /// <param name="callback">Callback for getting the enumerator, which is used for querying the parents of specified item.</param>
        public Enumerator(T initial, GetParentsEnumerator<T> callback)
        {
            notQueried.Enqueue(initial);
            this.initial = initial;
            GetParentsEnumeratorCallback = callback;
        }

        /// <summary>
        /// Gets the current element in the collection.
        /// </summary>
        public T Current
        {
            get { return current; }
        }

        bool disposed;
        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    current = default(T);
                    notQueried = null;
                    queried = null;
                    history = null;
                }
                disposed = true;
            }
        }

        /// <summary>
        /// Gets the current element in the collection.
        /// </summary>
        object System.Collections.IEnumerator.Current
        {
            get { return current; }
        }

        /// <summary>
        /// Skip same items
        /// </summary>
        public bool SkipSameItems { get; set; }

        /// <summary>
        /// Advances the enumerator to the next element of the collection.
        /// </summary>
        /// <returns>true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection. </returns>
        public bool MoveNext()
        {
            if (disposed) throw new ObjectDisposedException(null);
            if (rollbackHistory.Count > 0)
            {
                current = rollbackHistory.Dequeue();
                history.Enqueue(current);
                return true;
            }
            if (activeQuery != null)
            {
            here:
                if (activeQuery.MoveNext())
                {
                    if (SkipSameItems && history.Contains(activeQuery.Current)) { goto here; }
                    current = activeQuery.Current;
                    history.Enqueue(current);
                    notQueried.Enqueue(current);
                    return true;
                }
                else
                {
                    activeQuery = null;
                }
            }
            if (GetParentsEnumeratorCallback != null)
            {
                while (notQueried.Count != 0)
                {
                    T item = notQueried.Dequeue();
                    if (!queried.Contains(item))
                    {
                        IEnumerator<T> enumerator = GetParentsEnumeratorCallback(item);
                        queried.Add(item);
                        here:
                        if (enumerator != null)
                        {
                            if (enumerator.MoveNext())
                            {
                                activeQuery = enumerator;
                                if (SkipSameItems && history.Contains(enumerator.Current)) { goto here; }
                                current = enumerator.Current;
                                history.Enqueue(current);
                                notQueried.Enqueue(current);
                                return true;
                            }
                            else
                            {
                                enumerator = null;
                            }
                        }
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// Sets the enumerator to its initial position, which is before the first element in the collection. Keep all histories for caching.
        /// </summary>
        public void Reset()
        {
            if (disposed) throw new ObjectDisposedException(null);
            while (history.Count > 0)
            {
                rollbackHistory.Enqueue(history.Dequeue());
            }
            current = default(T);
        }

        /// <summary>
        /// Sets the enumerator to its initial position, which is before the first element in the collection. Reset all data, and close active sub-query.
        /// </summary>
        public void HardReset()
        {
            if (disposed) throw new ObjectDisposedException(null);
            queried.Clear();
            notQueried.Clear();
            notQueried.Enqueue(initial);
            history.Clear();
            activeQuery = null;
            current = default(T);
        }
    }
}

 

Download code and demo projects

Chorus本地模式版已经发布

Chorus是一个框架,它实现了多个部件之间的通讯功能。在它的协助下,软件系统中的每个部件可以自由通讯,而不论这些部件运行在同一个程序,同一台计算机,还是在世界的任何角落。

Chorus是一种模型,它展示了软件系统内部的物理结构。在它的支持下,软件系统中的每个部件可以随心拼装,而不论这些部件构造于您的产品,您的企业,还是获取自其他供应商。

Chorus是一份标准,它定义了每个程序部件的接口规格。在它的规范下,软件系统中的每个部件可以严格定义,而不论这些部件开发于同一个员工,同一个小组,还是来自外包公司。

 

当前已经发布本地模式版,实现同一个应用程序内部的通讯功能。

您有兴趣了解吗?请访问Chorus发布页

 

网络调试用工具包

注:以下软件均为较久前开发,需要dotNet Framework 1.1框架,不能兼容最新框架。

Redirector:TCP/UDP端口转发工具。

Smiler:TCP/UDP调试工具,支持作为客户端、服务器,并有多种编码支持。

UDPSimulator:UDP网络环境模拟器,通过对UDP包的转发,模拟网络上可能出现的丢包和顺序错位。