2008年7月23日

下面这段伪代码是我自己总结的,如果有错误请指出,谢谢

 

 1一定要分清楚C#编译器的要求和CLR的要求。C#的类型定位规则是:
 2    [方法]Type FindType(string fullname)::=在本程序集以及所有被引用的程序集中查找全名(完全限定名)为fullname的类型。本方法不会返回null,如果不存在符合条件的Type或者存在的Type多于一个,则抛出相应的异常。
 3    //level1
 4    If(typeIdentifier.startWith(“global::”))
 5    {    //如果类型标识符以’global::’开头,那么后面的部分构成一个类型全名
 6        //如果没有找到类型,则查找失败
 7        return FindType(typeIdentifier.removePrefixChar(8));
 8}

 9//level2
10// NamingContainer是能够在其中定义类型的构造
11// CurrentNamingContainer是包含本类型标识符的最近的类型定义容器(如home class)
12NamingContainer = CurrentNamingContainer;
13do
14{
15try
16{    //第一次查找是否是成员,而后依次在更上一级容器中查找
17    
18        return FindType (CurrentNameingContainer.Name  + “.”+ typeIdentifier);
19    }
finally{}
20}

21while(NamingContainer.parent != global)
22//最后一次查找是否是global中的类型,也就是用typeIdentifier本身作为全名查找
23    try
24{
25    return FindType (typeIdentifier);
26}
finally{}
27    //以上两个级别的查找先于使用using进行的查找的。
28
29//level3
30List<Type> list = new List<Type>(1);
31Foreach(usingNSPrefix in AllUsingNSPrefix)
32{    //所有由using语句引入的命名空间前缀是平级的
33    try
34    {
35        list.Add(FindType usingNSPrefix + “.” + (typeIdentifier));
36}
finally{}
37}

38if(list.Count > 1)
39{
40    throw new Exception(“类型名称歧义”);
41}

42if(list.Count == 0)
43{
44    throw new Exception(“没有找到类型”);
45}

46return list[0];
47//如果被引用的所有程序集中,定义了全名相同的类,那么在程序中不可引用这个类,否则无论如何会出现异常。根据FindType方法的定义可知,C#编译器是期待包括被编译模块在内的所有程序集中没有全名相同的类,否则FindType方法总会发生异常。
48

level2很巧妙,我们可以通过这个规则来实现一个类以覆盖原来的处于level3的类。

当然这是编辑时的把戏,必须要重新编译代码。

posted @ 2008-07-23 00:17 John Rambo 阅读(18) | 评论 (0)编辑

2008年7月17日

今天看CLR via C#,看到上面说,同一个类型会在不同应用程序域中存在多个映像,于是写了一段代码证明一下这个情况。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace RemotingTest
{
    
class Program
    
{
        
static void Main(string[] args)
        
{
            AppDomain ad 
= AppDomain.CreateDomain("AppDomain2");
            RemotingObj ro 
= ad.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, "RemotingTest.RemotingObj"as RemotingObj;//ro是本地的一个透明代理,指向新创建应用程序域中的对象
            Console.WriteLine(ro.IndexOf("Michael Jackson""Jack"));//到这里远程对象一定已经创建了,但是RemotingObj.Flag仍然为0,说明本应用程序域中的Type对象没有被设置,设定的是ad中的typeof(RemotingObj)
            bool flag = System.Runtime.Remoting.RemotingServices.IsTransparentProxy(ro);
            Console.WriteLine(flag);
            RemotingObj ro2 
= new RemotingObj();//本应用程序域中的对象
            flag = System.Runtime.Remoting.RemotingServices.IsTransparentProxy(ro2);
            Console.WriteLine(flag);
            
int a = ro.TypeHashCode();
            a 
= ro2.TypeHashCode();//通过F10可以看到hashcode变化了 说明typeof(RemotingObj)在不同appdomain中表示不同的对象
            Console.Read();
        }

    }


    
public class RemotingObj : MarshalByRefObject
    
{
        
public RemotingObj()
        
{
            RemotingObj.Flag 
= 112;
            Console.WriteLine(
string.Format("RemotingObj({0}) is created in {1}"this.GetHashCode(), AppDomain.CurrentDomain.FriendlyName));
        }


        
public int IndexOf(string str1, string str2)
        
{
            
return str1.IndexOf(str2);
        }


        
public int TypeHashCode()
        
{
            
return typeof(RemotingObj).GetHashCode();
        }


        
public static int Flag;
    }

}
posted @ 2008-07-17 14:15 John Rambo 阅读(56) | 评论 (0)编辑

2008年6月25日

     摘要: 控制台类似于socket,是由两个流组成的一个复合对象。“由两个流组成的复合对象”初看起来有点奇怪,仔细研究发现计算机中凡是实现双向通信的装置大都如此。流是单向的,是一端读取另一端的数据,或者说是另一端向一端写入数据。这只能实现单向的通信,成为单工。如果有了正反两个方向的流,就构成了一个双向通信的装置,成为双工。并且这个装置可以实现数据同时在两个方向上流动。还有一种通信通道... 阅读全文
posted @ 2008-06-25 23:30 John Rambo 阅读(94) | 评论 (0)编辑

2008年4月1日

        #region KMP generic

        private static int[] Next(IList<T> pattern)
        {
            int[] next = new int[pattern.Count];
            next[0] = -1;
            if (pattern.Count < 2) //如果只有1个元素不用kmp效率会好一些
            {
                return next;
            }

            next[1] = 0;    //第二个元素的回溯函数值必然是0,可以证明:
            //1的前置序列集为{空集,L[0]},L[0]的长度不小于1,所以淘汰,空集的长度为0,故回溯函数值为0
            int i = 2;  //正被计算next值的字符的索引
            int j = 0;  //计算next值所需要的中间变量,每一轮迭代初始时j总为next[i-1]
            while (i < pattern.Count)    //很明显当i==pattern.Length时所有字符的next值都已计算完毕,任务已经完成
            { //状态点
                //用Equals作为元素匹配条件
                if (pattern[i - 1].Equals(pattern[j]))   //首先必须记住在本函数实现中,迭代计算next值是从第三个元素开始的
                {   //如果L[i-1]等于L[j],那么next[i] = j + 1
                    next[i++] = ++j;
                }
                else
                {   //如果不相等则检查next[i]的下一个可能值----next[j]
                    j = next[j];
                    if (j == -1)    //如果j == -1则表示next[i]的值是1
                    {   //可以把这一部分提取出来与外层判断合并
                        //书上的kmp代码很难理解的一个原因就是已经被优化,从而遮蔽了其实际逻辑
                        next[i++] = ++j;
                    }
                }
            }
            return next;

        }

        public static int ExecuteKMP(IEnumerable<T> source, IList<T> pattern)
        {
            int[] next = Next(pattern);
            return ExecuteKMPInternal(source, pattern, next);
        }

        private static int ExecuteKMPInternal(IEnumerable<T> source, IList<T> pattern, int[] next)
        {
            IEnumerator<T> iterator = source.GetEnumerator();

            int i = iterator.MoveNext() ? 0 : -1;//这两条语句必须总是一起执行 //主串指针

            int j = 0;  //模式串指针
            //如果子串没有匹配完毕并且主串没有搜索完成
            while (j < pattern.Count && i > -1)
            {
                if (iterator.Current.Equals(pattern[j]))    //i和j的逻辑意义体现于此,用于指示本轮迭代中要判断是否相等的主串字符和模式串字符
                {
                    i = iterator.MoveNext() ? i + 1 : -1;
                    j++;
                }
                else
                {
                    j = next[j];    //依照指示迭代回溯
                    if (j == -1)    //回溯有情况,这是第二种
                    {
                        i = iterator.MoveNext() ? i + 1 : -1;
                        j++;
                    }
                }
            }
            //如果j==pattern.Length则表示循环的退出是由于子串已经匹配完毕而不是主串用尽
            return j < pattern.Count ? -1 : i - j;
        }

        /// <summary>
        /// 泛型版的Next函数
        /// </summary>
        /// <param name="pattern">模式串可以是一个实现了IList的对象,所有数组都实现了IList</param>
        /// <param name="isEqual">此函数必须是反映一个等价关系,即满足自反、传递、交换,否则算法会出现逻辑错误。这是KMP算法的前提。</param>
        /// <returns>返回Next回溯函数</returns>
        private static int[] Next(IList<T> pattern, Func<T, T, bool> isEqual)
        {
            int[] next = new int[pattern.Count];
            next[0] = -1;
            if (pattern.Count < 2) //如果只有1个元素不用kmp效率会好一些
            {
                return next;
            }

            next[1] = 0;    //第二个元素的回溯函数值必然是0,可以证明:
            //1的前置序列集为{空集,L[0]},L[0]的长度不小于1,所以淘汰,空集的长度为0,故回溯函数值为0
            int i = 2;  //正被计算next值的字符的索引
            int j = 0;  //计算next值所需要的中间变量,每一轮迭代初始时j总为next[i-1]
            while (i < pattern.Count)    //很明显当i==pattern.Length时所有字符的next值都已计算完毕,任务已经完成
            { //状态点
                //用Equals作为元素匹配条件
                if (isEqual(pattern[i - 1], pattern[j]))   //首先必须记住在本函数实现中,迭代计算next值是从第三个元素开始的
                {   //如果L[i-1]等于L[j],那么next[i] = j + 1
                    next[i++] = ++j;
                }
                else
                {   //如果不相等则检查next[i]的下一个可能值----next[j]
                    j = next[j];
                    if (j == -1)    //如果j == -1则表示next[i]的值是1
                    {   //可以把这一部分提取出来与外层判断合并
                        //书上的kmp代码很难理解的一个原因就是已经被优化,从而遮蔽了其实际逻辑
                        next[i++] = ++j;
                    }
                }
            }
            return next;

        }

        public static int ExecuteKMP(IEnumerable<T> source, IList<T> pattern, Func<T, T, bool> isEqual)
        {
            int[] next = Next(pattern, isEqual);
            return ExecuteKMPInternal(source, pattern, isEqual, next);
        }

        private static int ExecuteKMPInternal(IEnumerable<T> source, IList<T> pattern, Func<T, T, bool> isEqual, int[] next)
        {
            IEnumerator<T> iterator = source.GetEnumerator();

            int i = iterator.MoveNext() ? 0 : -1;//这两条语句必须总是一起执行 //主串指针

            int j = 0;  //模式串指针
            //如果子串没有匹配完毕并且主串没有搜索完成
            while (j < pattern.Count && i > -1)
            {
                if (isEqual(iterator.Current, pattern[j]))    //i和j的逻辑意义体现于此,用于指示本轮迭代中要判断是否相等的主串字符和模式串字符
                {
                    i = iterator.MoveNext() ? i + 1 : -1;

                    j++;
                }
                else
                {
                    j = next[j];    //依照指示迭代回溯
                    if (j == -1)    //回溯有情况,这是第二种
                    {
                        i = iterator.MoveNext() ? i + 1 : -1;
                        j++;
                    }
                }
            }
            //如果j==pattern.Length则表示循环的退出是由于子串已经匹配完毕而不是主串用尽
            return j < pattern.Count ? -1 : i - j;
        }

        private static int[] NextVal(IList<T> pattern)
        {
            int[] next = new int[pattern.Count];
            next[0] = -1;
            if (pattern.Count < 2) //如果只有1个元素不用kmp效率会好一些
            {
                return next;
            }

            next[1] = 0;    //第二个元素的回溯函数值必然是0,可以证明:
            //1的前置序列集为{空集,L[0]},L[0]的长度不小于1,所以淘汰,空集的长度为0,故回溯函数值为0
            int i = 2;  //正被计算next值的字符的索引
            int j = 0;  //计算next值所需要的中间变量,每一轮迭代初始时j总为next[i-1]
            while (i < pattern.Count)    //很明显当i==pattern.Length时所有字符的next值都已计算完毕,任务已经完成
            { //状态点
                //用Equals作为元素匹配条件
                if (j == -1 || pattern[i - 1].Equals(pattern[j]))   //首先必须记住在本函数实现中,迭代计算next值是从第三个元素开始的
                {   //如果L[i-1]等于L[j],那么next[i] = j + 1
                    j++;
                    if (pattern[i].Equals(pattern[j]))
                    {
                        next[i] = next[j];
                    }
                    else
                    {
                        next[i] = j;
                    }
                    i++;
                }
                else
                {   //如果不相等则检查next[i]的下一个可能值----next[j]
                    j = next[j];
                }
            }
            return next;
        }

        public static int ExecuteKMPP(IEnumerable<T> source, IList<T> pattern)
        {
            int[] next = NextVal(pattern);
            return ExecuteKMPInternal(source, pattern, next);
        }

        #endregion

刚才测试一下,貌似没有问题。

posted @ 2008-04-01 13:08 John Rambo 阅读(38) | 评论 (0)编辑

2008年3月31日

/// <summary>
        /// 求一个字符串的回溯函数。
        /// 约定序列下标从0开始。
        /// 回溯函数是整数集[0,n-1]到N的映射,n为字符串的长度。
        /// 回溯函数的定义:
        /// 设存在非空序列L,i为其合法下标;
        /// L[i]的前前置序列集为:{空集,L中所有以i-1为最后一个元素下标的子序列}
        /// L的前置序列集为:{空集,L中所有以0为第一个元素下标的子序列}
        /// 下标i的回溯函数值的定义为:
        /// 如果i=0,回溯函数值为-1
        /// 否则i的回溯函数值为i的前置序列集和L的前置序列集中相等元素的最大长度
        /// 换句话说是,设集合V={x,x属于i的前置序列集,并且x属于L的前置序列集,并且x的长度小于i},回溯函数值为max(V)
        /// 当i=0时并不存在这样的一个x,所以约定此时的回溯函数值为-1
        /// 回溯函数的意义:
        /// 如果标号为j的字符同主串失配,那么将子串回溯到next[j]继续与主串匹配,如果next[j]=-1,则主串的匹配点后移一位,同子串的第一个元素开始匹配。
        /// 同一般的模式匹配算法相比,kmp通过回溯函数在失配的情况下跳过了若干轮匹配(向右滑动距离可能大于1)
        /// kmp算法保证跳过去的这些轮匹配一定是失配的,这一点可以证明
        /// </summary>
        /// <param name="pattern">模式串,上面的注释里将其称为子串</param>
        /// <returns>回溯函数是kmp算法的核心,本函数依照其定义求出回溯函数,KMP函数依照其意义使用回溯函数。</returns>
        public static int[] Next(string pattern)
        {
            int[] next = new int[pattern.Length];
            next[0] = -1;
            if (pattern.Length < 2) //如果只有1个元素不用kmp效率会好一些
            {
                return next;
            }

            next[1] = 0;    //第二个元素的回溯函数值必然是0,可以证明:
            //1的前置序列集为{空集,L[0]},L[0]的长度不小于1,所以淘汰,空集的长度为0,故回溯函数值为0
            int i = 2;  //正被计算next值的字符的索引
            int j = 0;  //计算next值所需要的中间变量,每一轮迭代初始时j总为next[i-1]
            while (i < pattern.Length)    //很明显当i==pattern.Length时所有字符的next值都已计算完毕,任务已经完成
            { //状态点
                if (pattern[i - 1] == pattern[j])   //首先必须记住在本函数实现中,迭代计算next值是从第三个元素开始的
                {   //如果L[i-1]等于L[j],那么next[i] = j + 1
                    next[i++] = ++j;
                }
                else
                {   //如果不相等则检查next[i]的下一个可能值----next[j]
                    j = next[j];
                    if (j == -1)    //如果j == -1则表示next[i]的值是1
                    {   //可以把这一部分提取出来与外层判断合并
                        //书上的kmp代码很难理解的一个原因就是已经被优化,从而遮蔽了其实际逻辑
                        next[i++] = ++j;
                    }
                }
            }
            return next;
        }


        /// <summary>
        /// KMP函数同普通的模式匹配函数的差别在于使用了next函数来使模式串一次向右滑动多位称为可能
        /// next函数的本质是提取重复的计算
        /// </summary>
        /// <param name="source">主串</param>
        /// <param name="pattern">用于查找主串中一个位置的模式串</param>
        /// <returns>-1表示没有匹配,否则返回匹配的标号</returns>
        public static int ExecuteKMP(string source, string pattern)
        {
            int[] next = Next(pattern);
            int i = 0;  //主串指针
            int j = 0;  //模式串指针
            //如果子串没有匹配完毕并且主串没有搜索完成
            while (j < pattern.Length && i < source.Length)
            {
                if (source[i] == pattern[j])    //i和j的逻辑意义体现于此,用于指示本轮迭代中要判断是否相等的主串字符和模式串字符
                {
                    i++;
                    j++;
                }
                else
                {
                    j = next[j];    //依照指示迭代回溯
                    if (j == -1)    //回溯有情况,这是第二种
                    {
                        i++;
                        j++;
                    }
                }
            }
            //如果j==pattern.Length则表示循环的退出是由于子串已经匹配完毕而不是主串用尽
            return j < pattern.Length ? -1 : i - j;
        }

ps:个人认为kmp算法是一个很难的算法,证明它得需要2页纸。不过掌握和证明并不是一回事。

posted @ 2008-03-31 21:33 John Rambo 阅读(81) | 评论 (0)编辑

2008年3月26日

//节点是对某种类型数据的封装;通过这种封装,能够对这种数据建立树形模型
//Node是Data的马甲,穿上马甲的Data能够组织成一棵树
public abstract class Node<T>
    {
        protected T _data;

        public T Data
        {
            get
            {
                return _data;
            }

            set
            {
                _data = value;
            }

        }
    }


//定义子节点集合。这样定义节点有一个好处,如果获得一个节点的引用,也就引用的以该节点为根的整棵树

public class CldNode<T> : Node<T>
    {
        public CldNode(T data)
        {
            _data = data;
        }

        public CldNode()
        { }

        private List<CldNode<T>> _children;

        public List<CldNode<T>> Children
        {
            get
            {
                if (_children == null)    //从单例模式改的,不知道有没有问题?
                {
                    lock (this)
                    {
                        if (_children == null)
                        {
                            _children = new List<CldNode<T>>();
                        }
                    }
                }

                return _children;
            }
        }

    }

//后面使用堆栈模拟遍历树,这个辅助类定义了堆栈中的元素。
//First表示堆栈中的节点,Second表示要遍历这个节点的第几个子

[Serializable]
    public class Pair<FT, ST>
    {
        public Pair(FT first, ST second)
        {
            First = first;
            Second = second;
        }

        public FT First
        {
            get;
            set;
        }

        public ST Second
        {
            get;
            set;
        }
    }

//不用递归是因为不知道用递归改怎么写成迭代器
    public class CldNodeIterator<T>
    {
        private Stack<Pair<CldNode<T>, int>> _stack;
        private CldNode<T> _root;

        public CldNodeIterator(CldNode<T> root)
        {
            _root = root;
        }

        public CldNodeIterator() { }

        public CldNode<T> Root
        {
            get
            {
                return _root;
            }

            set
            {
                _root = value;
            }
        }

        //首先访问父节点
        //然后访问所有的子结点
        //上面这两点是递归的
        public IEnumerable<T> FPermiseTraverse()
        {
            if (_stack == null)
            {
                _stack = new Stack<Pair<CldNode<T>, int>>(16);
            }

            _stack.Push(new Pair<CldNode<T>, int>(_root, -1));

            while (_stack.Count != 0)
            {
                Pair<CldNode<T>, int> stkTop = _stack.Peek();

                if (stkTop.Second == -1) //尚未开始遍历
                {
                    yield return stkTop.First.Data;
                    stkTop.Second++;
                    continue;
                }

                if (stkTop.First.Children.Count == stkTop.Second)   //已经结束
                {
                    _stack.Pop();
                    if (_stack.Count != 0)
                    {
                        _stack.Peek().Second++;
                    }
                    continue;
                }

                _stack.Push(new Pair<CldNode<T>, int>(stkTop.First.Children[stkTop.Second], -1));
            }
        }

//先子后父
        public IEnumerable<T> CPermiseTraverse()
        {
            if (_stack == null)
            {
                _stack = new Stack<Pair<CldNode<T>, int>>(16);
            }

            _stack.Push(new Pair<CldNode<T>, int>(_root, -1));

            while (_stack.Count != 0)
            {
                Pair<CldNode<T>, int> stkTop = _stack.Peek();

                if (stkTop.Second == -1) //尚未开始遍历
                {
                    stkTop.Second++;
                    continue;
                }

                if (stkTop.First.Children.Count == stkTop.Second)   //已经结束
                {
                    yield return stkTop.First.Data;
                    _stack.Pop();
                    if (_stack.Count != 0)
                    {
                        _stack.Peek().Second++;
                    }
                    continue;
                }

                _stack.Push(new Pair<CldNode<T>, int>(stkTop.First.Children[stkTop.Second], -1));
            }

        }
    }
//不知道有没有bug?我没仔细测。

posted @ 2008-03-26 21:47 John Rambo 阅读(124) | 评论 (1)编辑

2008年3月4日

我试了一下,貌似没有问题。当然也很可能有问题,因为正则表达式我也是刚入门。
这个表达式是这样的:
^
[^<>]*
((?'open'<[^<>]*)+
(?'close-open'[^<>]*>)+)+
(?(open)(?!))$
作用是判定一个字符串中的尖括号是否配对,如果都配对则返回整个串,否则不返回任何匹配。
首先写下这个东西:
^
Expr
$
表示进行整串匹配,也就是要判断整个字符串是否符合Expr表示的模式。
哦,使用这个正则表达式的时候记得开启忽略空白字符。
如果正则表达式支持宏多好,把<>修改为()时就不用费太多力气了。
Expr::=
    Expr1::=[^<>]*
    Expr2::=(
                      (?'open'<[^<>]*)+
                      (?'close-open'[^<>]*>)+
                 )+
   Expr3::=(?(open)(?!))

[^<>]*不用多说,匹配'<'和'>'之外的任意字符任意多次,这并不是关键。
关键是Expr2。
Expr2中有两个关键构造,(?'Name'Expr)和(?'Name2-Name1'Expr)
第一个我称之为显式命名组,第二个人们称为平衡组。
这是.net framework特有的构造。
显式命名组将捕获到的文本存入名称为Name的堆栈中。所谓捕获到的文本,就是Expr所匹配的文本,(?'Name'Expr)和Expr的区别在于Expr捕获的文本没有存到一个堆栈中,或者说没有存到一个组中。
(?'Name2-Name1'Expr)除了将文本捕获到Name2组中,还pop名为Name的堆栈。
现在我们可以看看Expr2,其意义是“<[^<>]*”至少重复一次,后跟至少一个“[^<>]*>”。具几个匹配这个模式的例子:
<fsd<rew<bvc rewrew>ewr>
然后这整个东西---------->>   (?'open'<[^<>]*)+(?'close-open'[^<>]*>)+  <<----------可以重复多次。
可能说的不是太清楚,我觉得这一步很关键:
<[^<>]* 的实例可以是:<fsdfds、<、<rewrewrew、<fdsfsd dfsfds。
[^<>]*>的实例可以是:fdsfsd>、>、w-ww>。
现在你可以想象出来(<[^<>]*)+ ([^<>]*>)+是什么了。
而 (?'open'<[^<>]*)+(?'close-open'[^<>]*>)+  和它的唯一区别是,(?'open'...每匹配一次,就push该匹配结果到名为open的堆栈,(?'close-open'...每匹配一次,就从open堆栈pop一个元素。open堆栈是<与>是否配对的指示器。
最后Expr3这一部分判断open堆栈是否为空,为空则匹配成功,否则前向断言(?!),这总是导致匹配失败。





posted @ 2008-03-04 18:41 John Rambo 阅读(15) | 评论 (0)编辑

2008年2月27日

银行家舍入法即“四舍六入法”,可以概括为:“四舍六入五考虑,五后非零就进一,五后皆零看奇偶,五前为偶应舍去,五前为奇要进一”。
posted @ 2008-02-27 14:05 John Rambo 阅读(67) | 评论 (1)编辑
     摘要: Xpath是一门用于定址xml文档部分的语言,被设计由xslt和xpointer使用。
为了向xslt和xpointer共同需要的功能提供统一的语法和语义而设计了xpath。Xpath的主要功能是指称xml文档的(多个)部分。为了支持这一功能,xpath还提供了用于处理字符串、数字、布尔的基本机制。Xpath使用了一种紧凑的非xml语法以便使其便于在uri和xml属性值中使用。Xpath对xml文档的操作基于逻辑结构而不是字面语法。Xpath的名字来源自它作为url中的路径符号的用法,以在具有层次的xml文档中指称特定部分。  阅读全文
posted @ 2008-02-27 13:17 John Rambo 阅读(64) | 评论 (0)编辑

统计