2010年2月24日

深入理解CLR (1)

深入理解CLR

第一章  类型基础

1.  System.Object类型

所有类型都继承于System.Object,因此下面两种类型的定义方式是等价的。

//隐式从Object类继承

    class Employee

    {

    }

    //显式从Object类继承

    class Employee: Object

    {

}

 

除此之外,任何类型直接或间接继承于System.Object还可以保证任何类型的任何对象都有一组通用的方法,这些通用方法就是从System.Object类继承下来的。

 

2.  对象创建始末

CLR通过操作符new创建类型的实例(对象):

Employee emp = new Employee("constructor params");

 

这条语句创建了Employee类型的一个对象,并将指向该新建对象的引用存放在emp变量中。

下面是new操作符所作的工作:

1. 它计算类型及其所有基类型(最高至System.Object,虽然它没有定义自己的实例字段)中定义的所有实例字段需要的字节数。堆上每个对象都需要一些附加成员:类型对象指针和同步块索引。这些成员将由CLR用来管理对象,这些额外成员的字节数会加到对象大小上。

2. 它从托管堆中分配指定类型所需数量的字节来作为存储其对象的内存空间,分配的所有字节都置为0(二进制意义上的0)。

3. 初始化对象的附加成员。每一个对象都有两个附加成员,其中第一个成员为指向类型方法表的指针;第二个成员为同步块索引(注: CLR使用该成员来进行线程同步控制,该字段的某些位还用作垃圾收集时的标记,另外FCL中System.Object类型默认的GetHashCode方法也用到了该字段)。CLR使用这两个成员来管理对象实例。

4. 调用类型的构造函数,向其传入在new调用中指定的任何实参。大多数编译器会在构造函数中自动生成代码来调用其基类的构造函数。这样,最终会调用到System.Object的构造函数,该构造函数只是简单的返回。

new操作符执行了所有这些操作后,会返回对新创建的对象的一个引用(或指针)。

值得注意的是,new操作符没有相对应的delete操作符,换言之,没有办法显式释放为一个对象分配的内存,CLR采用了垃圾回收机制,能自动检测到一个对象不在被使用或访问,并自动释放对象内存。

[补充]

new操作符的用法:

1. 用于创建对象和调用其构造函数:

   Employee emp = new Employee( );

2. 用于创建匿名类型的实例:

  var query = from cust in customers

         select new {Name = cust.Name, Address = cust.PrimaryAddress};

3. 用于调用值类型的构造函数:

  int i = new int();     // 该语句效果等同于int i = 0;

注意:

(1)不能重载new运算符。

(2)如果new 运算符分配内存失败,将会引发OutOfMemoryException异常。

 

 

posted @ 2010-02-24 16:13 张念 阅读(68) 评论(0) 编辑

2010年2月3日

第三章 联接查询

第三章  联接查询

3.1 交叉连接(CROSS JOIN)

将一个输入表的每一行与另一个表的所有行进行匹配。如果一个表有m行,另一个表有n行,将得到m*n行的结果集。

ANSI-SQL语法:

SELECT C.custid,E.empid

FROM Sales.Customers AS C 

CROSS JOIN HR.Employees AS E

 

自交叉联接:

SELECT E1.empid, E1.firstname,E1.lastname , E2.empid,E2.firstname,E2.lastname

FROM HR.Employees AS E1 

CROSS JOIN HR.Employees AS E2

3.2 内联接(INNER JOIN)

ANSI-SQL语法:

SELECT E.empid, E.firstname,E.lastname,O.orderid,O.empid

FROM HR.Employees AS E 

JOIN Sales.Orders AS O

ON  E.empid = O.empid

 

【注意】ON子句只会返回令谓词结果为TRUE的行,而不会返回令谓词计算结果为FALSE或UNKNOWN得行。

3.4 外联接

逻辑处理步骤:

(1)笛卡尔积

(2)ON过滤

(3)添加外部行 : 识别保留表中按照ON条件在另一个表找不到与之匹配的那些行,再把这些行添加到联接的前两个步骤生成的结果集中。对于来自联接的非保留表的那些列,追加的外部行则用NULL作为占位符。

SELECT C.custid,O.orderid

FROM Sales.Customers AS C 

LEFT  OUTER  JOIN Sales.Orders AS O

 ON  C.custid = O.custid

WHERE  O.orderid IS NULL

从外联接保留表的角度来看,可以认为外联接结果集中的数据行包括两种:

(1)内部行:是按照ON子句中的条件能在另一边找到匹配的那些行。

(2)外部行:是指找不到匹配的那些行。

内联接只返回内部行;外联接同时返回内部行和外部行。

posted @ 2010-02-03 14:41 张念 阅读(63) 评论(0) 编辑

剖析.NET Framework源码—数据结构List<T> (四)

(17)Reverse:2个重载。将整个List或其一部分反转

public void Reverse(int index, int count)

        {

            if (index < 0 || count < 0)

                throw new ArgumentOutOfRangeException();

 

            if (_size - index < count)

                throw new ArgumentOutOfRangeException();

 

            Array.Reverse(_items, index, count);

 

            _version++;

        }

值得注意的是,原来索引为index的元素反转之后索引变为index+(index+count-i-1)!

 

(18)Sort:将List或其一部分进行排序

        //comparer为比较器,在元素相互比较过程中会用到

//如果比较器comparer为null,则排序过程中则使用元素的IComparable接  口进行比较,因此,必须保证数组中的所有元素都实现了IComparable接口

        public void Sort(int index, int count, IComparer<T> comparer)

        {

            if (index < 0 || count < 0)

            {

                throw new ArgumentOutOfRangeException();

            }

 

            if (_size - index < count)

                throw new ArgumentOutOfRangeException();

//使用Array.Sort方法对元素进行排序

            Array.Sort<T>(_items, index, count, comparer);

            _version++;

        }

 

//使用默认的比较器(元素的IComparable接口实现) 

        public void Sort()

        {

            Sort(0, Count, null);

        }

 

        // 使用提供的比较器comparer 

        public void Sort(IComparer<T> comparer)

        {

            Sort(0, Count, comparer);

        }

 

(20)TrimExcess:将容量设置为List中实际元素的个数

        //为了完全清除List中的元素并且释放list引用的全部内存,执行以下语句:

        // list.Clear(); 

        // list.TrimExcess();

        public void TrimExcess()

        {

            int threshold = (int)(((double)_items.Length) * 0.9);

 

            if (_size < threshold)

            {

                Capacity = _size;

            }

        }

 这个方法中有一个局部变量threshold,表示一个阈值,它是List容量的0.9倍!只有当List中实际存储的元素个数小于这个阈值时,List才会被紧缩!即是把List的容量设置为其实际存储元素的个数,以便节约内存空间。

 

(20)GetEnumerator:返回一个循环访问集合的枚举数

        public Enumerator GetEnumerator()

        {

 //利用当前List构造枚举数

            return new Enumerator(this);

        }

 

 

(21)Enumerator :用于循环访问集合的枚举数

[Serializable()]

        public struct Enumerator : IEnumerator<T>, System.Collections.IEnumerator

        {

            private List<T> list;

            private int index;      //当前的索引位置

            private int version;    //list的版本号

            private T current;      //当前元素

 

//构造出指定List的枚举数

            internal Enumerator(List<T> list)

            {

                this.list = list;

                index = 0;

                version = list._version;

                current = default(T);

            }

 

            public bool MoveNext()

            {

 

                List<T> localList = list;

//检查version值是否同步,如果不同步说明在枚举过程中对元素进  行了修改,则返回MoveNextRare方法,后者直接抛出异常

                if (version == localList._version && ((uint)index < (uint)localList._size))

                {

                    current = localList._items[index];

                    index++;

                    return true;

                }

                return MoveNextRare();

            }

 

            private bool MoveNextRare()

            {

                if (version != list._version)

                {

                    throw new InvalidOperationException();

                }

 

                index = list._size + 1;

                current = default(T);

                return false;

            }

 

            public T Current

            {

                get

                {

                    return current;

                }

            }

 

            Object System.Collections.IEnumerator.Current

            {

                get

                {

                    if (index == 0 || index == list._size + 1)

                    {

                        throw new InvalidOperationException();

                    }

                    return Current;

                }

            }

 

            void System.Collections.IEnumerator.Reset()

            {

                if (version != list._version)

                {

                    throw new InvalidOperationException();

                }

 

                index = 0;

                current = default(T);

            }

        }

 

(22)BinarySearch:对分检索算法在已排序的List或其一部分中查找特定元素!

        //利用二分查找算法搜索整个List或其一部分是否包含指定元素item!元素之间的相互比较时使用给定的comparer比较器,如果比较器为空,则使用元素的IComparable接口,因此数组元素和需要被查找的元素都要求实现IComparable接口,这个算法假设给定的List是有序的,否则结果会不正确!

//这个方法返回所要查找元素从0开始的索引,如果List中不包含此元素item,则返回一个负数!这个负数是List中大于item的第一个元素的索引的按位求补,如果没有更大的元素,则为count的按位求补。

        public int BinarySearch(int index, int count, T item, IComparer<T> comparer)

        {

            if (index < 0 || count < 0)

                throw new ArgumentOutOfRangeException();

            if (_size - index < count)

                throw new ArgumentException();

 

            return Array.BinarySearch<T>(_items, index, count, item, comparer);

        }

posted @ 2010-02-03 14:39 张念 阅读(315) 评论(0) 编辑

剖析.NET Framework源码—数据结构List<T> (三)

(8)FindIndex : 三个重载。搜索与指定谓词所定义的条件相匹配的元素,并返回   List<T>或它一部分中第一个匹配的元素从0开始的索引

 public int FindIndex(int startIndex, int count, Predicate<T> match)

        {

            if ((uint)startIndex > (uint)_size)

            {

                throw new ArgumentOutOfRangeException();

            }

 

            if (count < 0 || startIndex > _size - count)

            {

                throw new ArgumentOutOfRangeException();

            }

 

            if (match == null)

            {

                throw new ArgumentNullException();

            }

 

            int endIndex = startIndex + count;

 

            for (int i = startIndex; i < endIndex; i++)

            {

                if (match(_items[i])) 

return i;

            }

//如果遍历完成后仍找不到相匹配的元素,则返回 -1

            return -1;

        }

 

public int FindIndex(Predicate<T> match)

        {

            return FindIndex(0, _size, match);

        }

 

        public int FindIndex(int startIndex, Predicate<T> match)

        {

            return FindIndex(startIndex, _size - startIndex, match);

        }

(9)FindAll : 搜索与指定谓词所定义的条件相匹配的所有元素

 public List<T> FindAll(Predicate<T> match)

        {

            if (match == null)

            {

                throw new ArgumentNullException();

            }

//用于存储满足匹配条件的所有元素

            List<T> list = new List<T>();

            for (int i = 0; i < _size; i++)

            {

                if (match(_items[i]))

                {

                    list.Add(_items[i]);

                }

            }

            return list;

        }

(10)FindLastIndex : 三个重载。搜索与指定谓词定义的条件相匹配的元素,并  返回List<T>或它一部分中最后一个匹配元素从0开始的索引

 public int FindLastIndex(int startIndex, int count,                                 Predicate<T> match)

        {

            if (match == null)

            {

                throw new ArgumentNullException();

            }

 

            if (_size == 0)

            {

                if (startIndex != -1)

                {

                    throw new ArgumentOutOfRangeException();

                }

            }

            else

            {

                if ((uint)startIndex >= (uint)_size)

                {

                    throw new ArgumentOutOfRangeException();

                }

            }

 

            if (count < 0 || startIndex - count + 1 < 0)

            {

                throw new ArgumentOutOfRangeException();

            }

 

            int endIndex = startIndex - count;

   //从后往前搜索count个

            for (int i = startIndex; i > endIndex; i--)

            {

                if (match(_items[i]))

                {

                    return i;

                }

            }

            return -1;

        }

 

这个方法比较长,首先进行了很多的参数合法性验证,要注意startIndex - count + 1 = 0 这个临界条件。表示从startIndex向前搜索count个元素,若count等于startIndex+1,表示需要搜索startIndex之前(包括startIndex)的所有元素(至索引为0)!

该方法其他的重载形式为:

 public int FindLastIndex(Predicate<T> match)

        {

 //从最后一个元素向前搜索至第一个元素(索引位置为0)

            return FindLastIndex(_size - 1, _size, match);

        }

 

        public int FindLastIndex(int startIndex, Predicate<T> match)

        {

//从startIndex处(包括startIndex)向前搜索到第一个元素

            return FindLastIndex(startIndex, startIndex + 1, match);

        }

 

(11)T  FindLast(Predicate<T> match)

public T FindLast(Predicate<T> match)

        {

            if (match == null)

            {

                throw new ArgumentNullException();

            }

//从最后一个元素开始向前遍历

            for (int i = _size - 1; i >= 0; i--)

            {

                if (match(_items[i]))

                {

                    return _items[i];

                }

            }

//若搜索完毕后没有找到匹配元素,则返回泛型T的默认值

            return default(T);

        }

       与该方法类似,List中实现了一个Find方法,该方法同样搜索与指定谓词中定义的条件相匹配的元素,并返回整个List<T>中第一个匹配元素

public T Find(Predicate<T> match)

        {

            if (match == null)

            {

                throw new ArgumentNullException();

            }

 //从第一个元素向后遍历

            for (int i = 0; i < _size; i++)

            {

                if (match(_items[i]))

                {

                    return _items[i];

                }

            }

            return default(T);

        }

(12)Exists:确定List<T>是否包含与指定谓词所定义的条件相匹配的元素

public bool Exists(Predicate<T> match)

        {

            return FindIndex(match) != -1;

        }

(13)IndexOf :3个重载。返回 List或它的一部分中某个值的第一个匹配项的从   零开始的索引

//从index开始搜索count个元素

        public int IndexOf(T item, int index, int count)

        {

            if (index > _size)

                throw new ArgumentOutOfRangeException();

 

            if (count < 0 || index > _size - count) 

                throw new ArgumentOutOfRangeException();

 

            return Array.IndexOf(_items, item, index, count);

        }

 

        //从第一个元素开始搜索到最后一个元素

        public int IndexOf(T item)

        {

            return Array.IndexOf(_items, item, 0, _size);

        }

 

        int System.Collections.IList.IndexOf(Object item)

        {

            if (IsCompatibleObject(item))

            {

                return IndexOf((T)item);

            }

            return -1;

        }

//从index开始搜索到最后一个元素

        public int IndexOf(T item, int index)

        {

            if (index > _size)

                 throw new ArgumentOutOfRangeException();

            return Array.IndexOf(_items, item, index, _size - index);

        }

     与此方法类似的还有LastIndexOf的三种重载形式。返回 List或它的一部分中某个值的最后一个匹配项的从零开始的索引。

(14)RemoveAt:移除List指定索引处的元素

        public void RemoveAt(int index)

        {

            if ((uint)index >= (uint)_size)

            {

                throw new ArgumentOutOfRangeException();

            }

 

            _size--;

 

            if (index < _size)

            {

 //将index处后面的所有元素依次向前移一位

                Array.Copy(_items, index + 1, _items, index, _size - index);

            }

//最后一个多余的位置设置为泛型T的默认值

            _items[_size] = default(T);

            _version++;

        }

 

(15) Remove : 从List中移除特定对象的第一个匹配项 

        public bool Remove(T item)

        {

//首先找到该元素的第一个匹配项的索引

            int index = IndexOf(item);

            if (index >= 0)

            {

//移除List指定索引处的元素

                RemoveAt(index);

                return true;

            }

 

            return false;

        }

 

(16)RemoveAll:移除与指定的谓词所定义的条件相匹配的所有元素

这个方法是很有技巧的一个方法!

        public int RemoveAll(Predicate<T> match)

        {

            if (match == null)

            {

                throw new ArgumentNullException();

            }

 

            int freeIndex = 0;   

 

//freeIndex指定第一个需要被移除的元素的索引位置

            while (freeIndex < _size && !match(_items[freeIndex])) 

                freeIndex++;

//遍历完成后返回0,没有移除任何一个元素

            if (freeIndex >= _size) 

                return 0;

 

            int current = freeIndex + 1;

            while (current < _size)

            {

                // Find the first item which needs to be kept. 

                while (current < _size && match(_items[current]))  

                       current++;

 

                if (current < _size)

                {

                    _items[freeIndex++] = _items[current++];

                }

            }

 

            Array.Clear(_items, freeIndex, _size - freeIndex);

 

//已经移除的元素的个数

            int result = _size - freeIndex;

            _size = freeIndex;

            _version++;

            return result;

        }

posted @ 2010-02-03 02:35 张念 阅读(335) 评论(0) 编辑

剖析.NET Framework源码—数据结构List<T> (二)

接着,我们看看List中对数据进行操作的方法:

(2)Add:将对象添加到 List<T>的结尾处。

        public void Add(T item)

        {

            if (_size == _items.Length) EnsureCapacity(_size + 1);

            _items[_size++] = item;      

            _version++;

        }

这个方法有两个要点:

1. 当前List已满(_size==_items.Length)时,首先需要进行扩容!

2. 往List内部数组_items中添加新元素的操作_items[_size++] = item存在        多线程并发访问的问题!

(3)AddRange:将指定集合的元素添加到 List的末尾

        public void AddRange(IEnumerable<T> collection)

        {

            InsertRange(_size, collection);

        }

这个方法对collection不做任何处理,直接调用InsertRange方法。

(4)InsertRange : 将集合中的所有元素插入List的指定索引处。

// Inserts the elements of the given collection at a given index. If

        // required, the capacity of the list is increased to twice the previous

        // capacity or the new size, whichever is larger.  Ranges may be added 

        // to the end of the list by setting index to the List's size. 

        public void InsertRange(int index, IEnumerable<T> collection)

        {

            if (collection == null)

            {

                throw new ArgumentNullException();

            }

 

            if ((uint)index > (uint)_size)

            {

                throw new ArgumentOutOfRangeException();

            }

 

            ICollection<T> c = collection as ICollection<T>;

            if (c != null)

            {    

                int count = c.Count;

                if (count > 0)

                {

                    EnsureCapacity(_size + count);

 

                    if (index < _size)

                    {

                        Array.Copy(_items, index, _items, index + count, _size - index);

                    }

 

                    if (this == c)

                    {

                        Array.Copy(_items, 0, _items, index, index);

                        Array.Copy(_items, index + count, _items, index * 2, _size - index);

                    }

 

                    else

                    {

                        T[] itemsToInsert = new T[count];

                        c.CopyTo(itemsToInsert, 0);

                        itemsToInsert.CopyTo(_items, index);

                    }

                    _size += count;

                }

            }

            else

            {

                using (IEnumerator<T> en = collection.GetEnumerator())

                {

                    while (en.MoveNext())

                    {

                        Insert(index++, en.Current);

                    }

                }

            }

            _version++;

        }

这个方法很长,不过其思路是很清晰的。首先进行两次参数合法性验证,如果某次验证失败了,就直接抛个异常出去。注意第二个合法性检查,它检查的是要插入collection元素到List的指定索引位置index,其合法区间是[0 , _size]!

接着,会把传入的collection尝试转 换为ICollection<T>接口,如果转换成功,说明collection实现了ICollection接口,那么就执行if语句块;否则,执行else语句块。

If语句块的基本思路是:首先获得collection中元素的个数count,接着调用EnsureCapacity(_size + count)以确定是否需要扩容,然后根据所要插入的索引位置index在内部数组_items中腾出count个位置以便存储collection中的元素。紧接着创建一个itemsToInsert辅助数组用于存放collection中的所有元素,然后把itemsToInsert中所有的元素(count个)拷贝到List的内部数组_items中早已腾出的空间中(count个位置)。最后再把_size的值加上count。注意,在if语句块中我们还有一个地方未涉及到,就是if (this == c)大括号中的代码,这是一种特殊情况,表示要插入的collection就是当前这个List,分析思路类似!

else语句块的思路是:利用collection的迭代器,将collection中的元素一个一个插入到_items数组的指定索引index位置后面!注意这里会调用到Insert方法,这也是List的核心方法之一。

(5)Insert(int index, T item):将元素插入List的指定索引处

        public void Insert(int index, T item)

        {

            // index的合法区间是[0 , _size]

            if ((uint)index > (uint)_size)

            {

                throw new ArgumentOutOfRangeException();

            }

 

            if (_size == _items.Length) EnsureCapacity(_size + 1);

 

            if (index < _size)

            {

// index处及后面所有元素后移一位,腾出index这个位置!

                Array.Copy(_items, index, _items, index + 1, _size - index);

            }

 

 //要插入的元素就放在指定的index位置处!

            _items[index] = item;

            _size++;

            _version++;

        }

(6)CopyTo :三个重载,将 List或它的一部分复制到一个数组中

    //参数array : 目标数组

    //参数arrayIndex : 目标数组开始放置处的索引

 public void CopyTo(T[] array, int arrayIndex)

        {

            Array.Copy(_items, 0, array, arrayIndex, _size);

        }

    //参数index : 源List中复制开始位置的从零开始的索引

    //参数count : 要复制的元素个数

public void CopyTo(int index, T[] array, int arrayIndex, int count)

        {

            if (_size - index < count)

            {

                throw new ArgumentException();

            }

            Array.Copy(_items, index, array, arrayIndex, count);

        }

        //将整个List复制到类型兼容的一维数组中,从目标数组的0索引开始放置

 public void CopyTo(T[] array)

        {

            CopyTo(array, 0);

        }

(7)Contains(T item) : 确定某元素是否在List中

    public bool Contains(T item)

        {

            if ((Object)item == null)

            {

                for (int i = 0; i < _size; i++)

                {

                    if ((Object)_items[i] == null)

                        return true;

                }

                return false;

            }

            else

            {

                EqualityComparer<T> c = EqualityComparer<T>.Default;

 

                for (int i = 0; i < _size; i++)

                {

                    if (c.Equals(_items[i], item)) return true;

                }

                return false;

            }

        }

     该方法有两条执行路径。当所要查找的元素为null时执行if语句块;否则执行else语句块。

 两条执行路径的基本思路都是一样的:遍历List内部数组,如果找到了所要查找的元素,则返回True!注意else语句块,首先获得了一个泛型T的相等性比较器EqualityComparer<T>,然后通过相等性比较器的Equals方法比较两个对象是否相等!

posted @ 2010-02-03 01:43 张念 阅读(410) 评论(0) 编辑

剖析.NET Framework源码—数据结构List<T> (一)

List<T>类表示可通过索引访问的对象的强类型列表。提供对列表进行搜索,排序和操作的方法。

 

//List<T>内部使用一个泛型数组T[]来存储元素。为这个内部数组分配的长度就    

  是List的容量Capacity(最大能存储的元素个数),当向这个List添加新元素

  时.如果List已满或无法再添加更多元素,该List的容量就会按照某种机制自动

  增长以便容纳更多的新元素,其容量的增长是通过重新分配内部数组T[]实现的。

    public class List<T> : IList<T>, System.Collections.IList 

    {

 

        private const int _defaultCapacity = 4;

 

        private T[] _items;

        private int _size;    

        private int _version;

 

        static T[] _emptyArray = new T[0];

 }

 

以上是List<T>的四个私有字段和一个静态字段:

(1)_items 就是List内部实际存储元素的地方——数组。我们往List里面添加元素,其实就是将元素放到List内部的数组中。

(2)_size 表示内部数组中实际存储的元素个数。注意这个_size与Capacity的区别!

(3)_version可以理解为版本号。这个版本号存在的目的是为了保证在对该List进行迭代的过程中不对其原有元素进行修改。

(4)_defaultCapacity表示该List默认的容量。

(5)_emptyArray就是一个长度为0的空数组!

 

【构造函数】

接着我们看看List的构造函数:

(1)默认无参构造函数 

//构造一个List。这个List初始为空并且容量为0。

        public List()

        {

            _items = _emptyArray;

        }

 

(2)参数表示List的容量的构造函数

        //用一个指定的初始容量capacity构造List。

        public List(int capacity)

        {

            if (capacity < 0) 

                throw new ArgumentOutOfRangeException();

            _items = new T[capacity];

        }

(3)用一个实现了IEnumerable接口的collection构造List

//构造一个List,并将collection中的所有元素复制到List中,这个新List  的size和capacity都等于给定collection的大小。

        public List(IEnumerable<T> collection)

        {

            if (collection == null)

                throw new ArgumentNullException();

 

            ICollection<T> c = collection as ICollection<T>;

            if (c != null)

            {

                int count = c.Count;

                _items = new T[count];

                c.CopyTo(_items, 0);

                _size = count;

            }

            else

            {

                _size = 0;

                _items = new T[_defaultCapacity];

 

                using (IEnumerator<T> en = collection.GetEnumerator())

                {

                    while (en.MoveNext())

                    {

                        Add(en.Current);

                    }

                }

            }

        }

让我们来分析一下这个相对比较复杂的构造函数。首先进行的是参数合法性验证,这里只简单的检查了传入的collection是否为空;紧接着会尝试着将collection转换成ICollection接口,如果转换成功,执行if语句中的代码,转换失败则执行else语句中的代码!

假设转换成功,则说明传入的参数collection是实现了ICollection接口的。接下来的代码很简单,大概就是分配一个数组,该数组的长度就是collection中元素的个数,接着把collection中的元素全部拷贝到新分配的数组中。

如果转换失败,那么执行else语句块。首先会按照默认容量_defaultCapacity分配一个新数组,接着利用collection的枚举器将collection中的元素一个一个添加到新分配的数组中。

 

【属性】

接着,我们介绍List中几个比较重要的属性

(1)Capacity:代表List的容量。即是其内部数组_items的长度。

//获取或设置该List的容量,当设置时,其内部数组会按照指定value重新分  配。 

        public int Capacity

        {

            get { return _items.Length; }

 

            set

            {

                if (value != _items.Length)

                {

                    if (value < _size)

                    {

                        throw new ArgumentOutOfRangeException();

                    }

 

                    if (value > 0)

                    {

                        T[] newItems = new T[value];   //reallocate

 

                amp;nbsp;        if (_size > 0)

                        {

                            Array.Copy(_items, 0, newItems, 0, _size);

                        }

                        _items = newItems;

                    }

                    else

                    {

                        _items = _emptyArray;

                    }

                }

            }

        }

当设置Capacity时,首先会进行合法性验证,值得注意的是,当要设置的Capacity的值value小于当前List的实际元素个数_size时,会抛出异常!接着,按照value的值重新分配一个新数组newItems,然后把原来数组_items中的所有元素(_size个)全部拷贝到新数组newItems中。旧数组随后被抛弃,等待GC回收。

(2)Count

 //只读属性。简单的返回_size,用于描述List中实际有多少个元素。

        public int Count

        {

            get { return _size; }

        }

(3)Item:获取或设置指定索引处的元素

 public T this[int index]

        {

            get

            {

 

                if ((uint)index >= (uint)_size)

                {

                   throw new ArgumentOutOfRangeException();

                }

                return _items[index];

            }

            set

            {

                if ((uint)index >= (uint)_size)

                {

                    throw new ArgumentOutOfRangeException();

                }

                _items[index] = value;

                _version++;

            }

        }

    以上代码都很简单,值得说明的一点是当每次设置指定索引处的元素值时,字段_version都会加1,表示该List又被修改了一次。其具体作用会在List的迭代器中详细说明。

重要方法】

首先,我们展示两个私有方法:

(1)IsCompatibleObject 

//判断对象value的类型是否与数组类型T相容
private static bool IsCompatibleObject(object value)

        {

            if ((value is T) || (value == null && !typeof(T).IsValueType))

            {

                return true;

            }

            return false;

        }

可以看到。类型value与数组类型T相容有以下2种情况:

1. value的类型就是T类型或是T类型的子类

2. value为null时,数组类型T必须是引用类型

 

(2)VerifyValueType

//利用上面的IsCompatibleObject方法进行对象类型相容性检查

private static void VerifyValueType(object value)

        {

            if (!IsCompatibleObject(value))

            {

                throw new ArgumentException();

            }

        }

 

然后,我们看看在List中比较重要的公共方法:

首先,我们看一个List用于扩展其容量的方法,这个方法很重要,决定了List的性能。

(1)EnsureCapacity

//确保List的容量至少为给定的最小值min。

//如果List的当前容量比给定最小值min小,那 么其容量会增至当前容量的两倍,或是增至最小值min。

        private void EnsureCapacity(int min)

        {

            if (_items.Length < min)

            {

                int newCapacity = _items.Length == 0 ? _defaultCapacity : _items.Length * 2;

                if (newCapacity < min) newCapacity = min;

                Capacity = newCapacity;

            }

        }

上面的代码首先确定List新的容量newCapacity是多少,然后设置List的属性Capacity的值为newCapacity。

newCapacity值的确定过程是很简单却又十分曲折!

1. 如果当前的List是才被new出来,还没有添加任何元素,那么_items.Length等于0,

  此时newCapacity的值会被设置为默认容量_defaultCapacity=4。

2. 如果数组中已经有了元素,那么newCapacity的值会被设置为当前容量的两倍。

3. 如果经过计算后newCapacity仍然小于给定的最小值min,那么就直接把newCapacity的值设置为给定的最小值min。

posted @ 2010-02-03 01:40 张念 阅读(472) 评论(0) 编辑

2010年1月25日

第二章 单表查询

第二章  单表查询

2.1 SELECT语句的元素

   SELECT语句的目的是对表进行查询,应用一定的逻辑处理,并返回结果。

示例1 示例查询

USE TSQLFundamentals2008;

 

SELECT empid,YEAR(orderdate) AS orderyear , COUNT(*) AS numorders

FROM Sales.Orders

WHERE custid = 71

GROUP BY empid,YEAR(orderdate)

HAVING COUNT(*) > 1

ORDER BY empid,orderyear;

各子句在逻辑上按一下顺序进行处理:

1. FROM

2. WHERE

3. GROUP BY

4. HAVING

5. SELECT

6. ORDER BY

逻辑上应该按照一下顺序进行处理:

FROM Sales.Orders

WHERE custid = 71

GROUP BY empid,YEAR(orderdate)

HAVING COUNT(*) > 1

SELECT empid,YEAR(orderdate) AS orderyear , COUNT(*) AS numorders

ORDER BY empid,orderyear

 

2.1.1 FROM子句

     在FROM子句中指定想要查询的表名,在SELECT子句中指定想要返回的各个属性。

  SELECT orderid,custid,empid,orderdate,freight FROM Sales.Orders

2.1.2 WHERE子句

     只有能让逻辑表达式返回TRUE的行,才能由WHERE阶段返回给后续的逻辑处理阶段。

     SELECT orderid,empid,custid,freight FROM Sales.Orders WHERE custid=71 

     T-SQL使用的是三值谓词逻辑: TRUE   FALSE   UNKNOWN。

     【注意】  TRUE  !=  NOT FALSE

2.1.3 GROUP BY子句

     GROUP BY阶段可以将前面逻辑查询处理阶段返回的行按“组”进行组合。每个组由在GROUP BY子句中指定的各元素决定。

 如果涉及到分组,那么GROUP BY阶段之后的所有阶段(包含HAVING,SELECT以及ORDER BY)的操作对象都是组,而不是单独的行。 

因为聚合函数只为每个组返回一个值,所以一个元素如果不在GROUP BY列表中出现,就只能作为聚合函数(COUNT,MAX,SUM,AVG,MIN)的输入。

所有的聚合函数都会忽略NULL值,只有一个例外——COUNT(*)

SELECT empid,YEAR(orderdate),SUM(freight),COUNT(*) AS orderdate

FROM Sales.Orders

WHERE custid=71

GROUP BY empid,YEAR(orderdate)

YEAR函数orderdate列的年份部分。

 

SELECT empid,YEAR(orderdate),COUNT(DISTINCT custid)

FROM Sales.Orders

GROUP BY empid,YEAR(orderdate)

如果只想处理不重复的已知值,可以在聚合函数括号中指定DISTINCT 关键字。

2.1.3 HAVING子句

只有能让逻辑表达式返回TRUE的组,才能由HAVING阶段返回给后续的逻辑处理阶段。

    SELECT empid,YEAR(orderdate)

FROM Sales.Orders

WHERE custid=71

GROUP BY empid,YEAR(orderdate)

HAVING COUNT(*)>1

2.1.5 SELECT子句

SELECT子句用于指定需要在查询返回的结果集中包含的属性(列)。

为目标列取别名: 表达式  AS  别名(最佳实践)

【注意】SELECT子句是在FROM,WHERE,GROUP BY以及HAVING子句之后处理的,这意味着对于SELECT子句之前处理的那些子句,在SELECT子句中为表达式分配的别名并不存在。

错误示例1:

SELECT orderid,YEAR(orderdate) as orderyear

FROM Sales.Orders

WHERE orderyear>2006

解决办法是使用同一个表达式:

SELECT orderid,YEAR(orderdate) as orderyear

FROM Sales.Orders

WHERE YEAR(orderdate)>2006

 

在SELECT子句内部也不能引用同一SELECT子句中创建的别名列。

错误示例2:

SELECT YEAR(orderdate) AS orderyear,orderyear+1 AS nextyear

FROM Sales.Orders

为了确保SELECT语句执行的结果中行的唯一性,SQL提供的方法就是使用DISTINCT子句来删除多余的行。

SELECT DISTINCT empid , YEAR(orderdate) AS orderyear

FROM Sales.Orders

2.1.6 ORDER BY子句

ORDER BY子句用于展示数据时对输出结果中的行进行排序(升序ASC和降序DESC)。

ORDER BY子句是唯一能引用SELECT处理阶段创建的列别名的阶段,因为它是唯一一个在SELECT阶段之后被处理的阶段。

SELECT empid,YEAR(orderdate) AS orderyear

FROM Sales.Orders

ORDER BY empid,orderyear ASC

T-SQL支持在ORDER BY子句中指定没有在SELECT子句中出现过的元素。也就是说,排序依据的列并不一定要在输出返回的列中选取。

SELECT firstname,lastname,country

FROM HR.Employees

ORDER BY hiredate DESC;

【注意】

当指定了DISTINCT以后,ORDER BY子句就被限制为只能选取SELECT列表中出现的那些元素。

错误示例3:

SELECT DISTINCT country 

FROM HR.Employees

ORDER BY hiredate;

2.1.7 TOP选项

    TOP选项是T-SQL特有的,用于限制查询返回的行数或百分比。

从逻辑查询的角度来看,TOP选项是作为SELECT阶段的一部分而处理的,紧挨着DISTINCT子句处理之后(如果存在DISTINCT)。

【注意】

当在查询中指定了TOP之后,ORDER BY子句就会起到双重作用。

(1)作为SELECT处理阶段的一部分的TOP选项要依靠ORDER BY子句先为各个行定义它们的逻辑优先顺序,在这种顺序的基础上再去过滤其他请求。

(2)作为SELECT处理阶段之后的ORDER BY阶段,与为了展示数据而对行进行排序的ORDER BY子句完全一样。

SELECT TOP(5) orderid,orderdate 

FROM Sales.Orders

ORDER BY orderdate DESC

 

在TOP中可以使用PERCENT关键字,在这种情况下,SQL Server会按照百分比来计算应该返回的满足条件的行数(向上取整)。

SELECT TOP(2) PERCENT orderid,orderdate

FROM Sales.Orders

ORDER BY orderdate DESC

 

如果想让查询是确定的,就要让ORDER BY列表能唯一的决定一行。换句话说,就是要为ORDER BY列表增加一个附加属性(附加属性是一个允许唯一的排列元素的属性或属性列表)。

WITH TIES选项:

SELECT TOP(5) WITH TIES orderid,orderdate

FROM Sales.Orders

ORDER BY orderdate DESC;

 

 

2.1.7 OVER子句

 OVER子句用于为行定义一个窗口,以便进行特定的运算。可以把行的窗口简单的认为是运算将要操作的一个行的集合。

聚合开窗函数使用OVER子句提供窗口作为上下文,对窗口中的一组值进行操作,而不是使用GROUP BY子句提供的上下文。这样就不必对数据进行分组,还能在同一行中同时返回基础行的列和聚合列。

带有空括号的OVER子句会提供所有的行进行计算。这里的所有的行并不一定是在FROM子句中出现的那些表中的所有行,而是在FROM,WHERE,GROUP BY,HAVING处理阶段完成之后仍然可用的那些行。

只有在SELECT阶段和ORDER BY阶段才允许使用OVER子句。

SELECT orderid,custid,val,SUM(val) OVER() AS total ,SUM(val) OVER(PARTITION BY custid) AS custtotalvalue

FROM Sales.OrderValues

 

OVER子句的一个优点就是:

(1)能够在返回基本列的同时,在同一个行对它们进行聚合。

(2)也可以在表达式中混合使用基本列和聚合值列。

SELECT  orderid,custid,val,100.*val / SUM(val) OVER() , 100.*val/SUM(val) 

     OVER(PARTITION BY custid)

FROM Sales.OrderValues; 

 OVER也支持四种排名函数:

ROW_NUMBER:用于为查询的结果集的各行分配递增的序列号,其逻辑顺序通过OVER子句中的ORDER BY语句进行指定。

SELECT orderid,custid,ROW_NUMBER() OVER(ORDER BY orderid) AS rownumber

FROM Sales.OrderValues

RANK和DENSE_RANK:RANK表示之前具有多少行更低的排序值

       DENSE_RANK表示之前具有多少个更低的排序值

SELECT orderid,custid,val ,ROW_NUMBER() OVER(ORDER BY val) AS rownumber,

   RANK() OVER(ORDER BY custid) AS rank,

   DENSE_RANK() OVER(ORDER BY custid) AS denserank

FROM Sales.OrderValues

 

 

【注意】

RANK和DENSE_RANK不同于ROW_NUMBER的地方是:

RANK和DENSE_RANK为具有相同排序值的所有行生成同一个序列号!

NTILE:可以把结果集中的行关联到组(tile,相当于由行组成的指定数目的组),并为每一行分配一个所属组的编号。

SELECT orderid,custid,val,NTILE(10) OVER(ORDER BY val)

FROM Sales.OrderValues

 

posted @ 2010-01-25 20:37 张念 阅读(166) 评论(0) 编辑

SQL Server 2008技术内幕:T-SQL语言基础 笔记

1.1 SQL Server 2008实例

    SQL Server实例是指安装的一个SQL Server数据库引擎/服务。在同一台计算机上可以安装SQL Server的多个实例,从安全性,实例管理的数据以及其他方面来说,每个实例之间是彼此独立的。

    可以将计算机上安装的实例之一设置为默认实例,而其他实例则必须为命名实例

    在安装期间中可以决定是将一个实例安装为默认实例,还是命名实例,但安装好后就不能对此进行修改了!

    客户端应用程序连接默认实例:   计算机名(IP地址)

    客户端应用程序连接命名实例:   计算机名(IP地址) \ 实例名称(安装期间提供)


1.2数据库

    可以认为数据库是各种对象的容器,这些对象可以是:表,视图,存储过程等等。每个SQL Server实例可以包含多个数据库。

    安装SQL Server时安装程序会创建几个系统数据库,用于保存系统数据和服务于内部目的。


1.2.1系统数据库

    master : 保存实例范围内的元数据信息,服务器配置,实例中所有数据库的信息,以及初始化信息。

    resource : 是SQL Server 2005新增的,用于保存所有系统对象。当查询数据库中的元数据信息时,这种信息表面上是位于数据库中的,但实际上是保存在resource数据库中的。

    model : 是新数据库的模板,每个新创建的数据库最初都是model的一个副本(Copy)。

    tempdb : 是保存临时数据的地方。每次重新启动SQL Server实例时,会删除这个数据库 的内容,并将其创建为model 的一个副本。 

    msdb : 是称为SQL Server Agent的一种服务保存其数据的地方。


1.2.2登陆验证

    从安全性方面,为了能连接到SQL Server实例,必须让DBA位用户创建一个登陆账号。登陆账号可以关联到Windows凭据(credentials),在这种情况下,它会调用Windows凭据进行身份验证。

    当使用SQL Server验证登陆来连接SQL Server实例时,就必须提供登陆的用户名密码


1.2.3物理布局

    数据库在物理上是由数据文件事务日志文件组成。

    每个数据库必须至少有一个数据文件和一个日志文件(SQL Server的默认情况),数据文件用于保存数据库对象数据,事务日志文件则保存SQL Server为了维护事务所需的信息

    .mdf 代表Master Data File(主要数据文件)。

    .ldf 代表Log Data File(日志数据文件)

    .ndf 代表Not Master Data File(辅助数据文件)

 

1.2.4 架构和对象

一个数据库包含多个架构,而每个架构则又包含多个对象(表,视图,存储过程等)。

架构一个命名空间,用作对象名称的前缀。例如,在架构Sales中有一个Order表,架构限定(schema-qualified)的对象名称是Sales.Order。如果在引用对象时忽略了架构名称,SQL Server将按照一定的策略分析出架构的名称是什么。

如果不显式的指定架构,那么在解析对象名称时就会付出一定的没有意义的额外代价。所以在代码中引用对象时,总是推荐使用这种架构限定的对象名称(两部分对象名称)。

 

1.3 创建表和定义数据完整性

示例1:创建数据库

IF DB_ID ( 'testdb' ) IS NULL

CREATE DATABASE testdb ;

(1)检查数据库是否存在?

DB_ID函数接受一个数据库名称作为输入参数,返回它的内部数据库ID。如果指定名称的数据库还不存在,则返回NULL

(2)架构?

这个例子使用的架构是dbo(默认架构),在每个数据库中都会自动创建这个架构。

 

1.3.1创建表

示例2:创建表

USE testdb ; 

IF  OBJECT_ID( 'dbo.Employees' ,'U' )  IS NULL

    DROP  TABLE  dbo.Employees ;

CREATE  TABLE  dbo.Employees

(

empid   INT   NOT NULL,

firstname  VARCHAR(30)   NOT NULL,

lastname  VARCHAR(30)   NOT NULL,

hiredate   DATE   NOT NULL,

mgrid   INT   NOT NULL,

ssn      VARCHAR(2)   NOT NULL,

salary   MONEY    NOT NULL

) ;

【示例分析】

(1)USE 语句将当前的数据库上下文切换为dbo.testdb。以确保在正确的数据库中创建对象。

(2)OBJECT_ID函数接受一个对象名称和类型作为输入,这里,类型 ' U '代表用户表。如果匹配给定输入名称和类型的对象存在,这个函数则返回内部的对象ID,否则返回NULL。

(3)CREATE  TABLE 先指定要创建的表的名称(架构限定名),然后再在圆括号中定义它的各个属性(列)。

【ANSI标准】

如果不显式指定一个列是否允许NULL值,则假设应该是NULL值(允许NULL值)。

【最佳实践】

将列定义为为NOT NULL

采用分号结束所有语句

 

1.3.2定义完整性约束

(1)Primary Key Constraints

     主键约束实施行的唯一约束,同时不允许受约束的属性(列)取NULL值。

 每个表只能定义一个主键.

 ALTER TABLE dbo.Employees

ADD  CONSTRAINT PK_Employees

PRIMARY KEY(empid);

     定义好主键约束后,就可以保证所有的empid的值是唯一而确定的。

(2)Unique Constraints

 唯一约束用来保证数据行的一个列(一组列)数据的唯一。

 在同一个表中可以定义多个唯一约束。

ALTER TABLE dbo.Employees

ADD  CONSTRAINT UNQ_Employees_ssn

UNIQUE(ssn);

(3)Foreign Key Constraints

     外键约束用于实施引用完整性。这种约束在引用表(referencing table)的一组属性上进行定义,并指向被引用表(referenced table)中的一组候选键(主键或唯一约束)。注意,引用表和被引用表可能是同一个表!

     外键的目的是将外键列允许的值域限制为被引用列中现有的那些值。

示例3:创建表Order,其主键定义在orderid上

IF OBJECT_ID('dbo.Orders','U') is NOT NULL

DROP TABLE dbo.Orders;

 

CREATE TABLE dbo.Orders

(

orderid INT NOT NULL,

empid INT NOT NULL,

custid VARCHAR(20) NOT NULL,

orderts DATETIME NOT NULL,

qty INT NOT NULL,

CONSTRAINT PK_Orders

PRIMARY KEY(orderid)

);

如果现在要想实施一个完整性规则,将Orders表的empid列支持的值域限制为现有的Employees表中empid列的取值。为此,要在Orders表的empid上定义一个外键约束,让他指向Employees表的empid列。

ALTER TABLE dbo.Orders

ADD CONSTRAINT FK_Orders_Employees

FOREIGN KEY(empid) REFERENCES dbo.Employees(empid);

 

类似的,想要限制Employees表中mgrid列支持的值域为同一个表中已经存在的那些empid的值。

ALTER TABLE dbo.Employees

ADD CONSTRAINT FK_Employees_Employees

FOREIGN KEY(mgrid) 

REFERENCES dbo.Employees(empid);

 

注意,既是被引用的候选键列不存在NULL值,在外键列中也允许NULL列。

【禁止操作】

当试图删除被引用表中的行,或更新被引用的候选键时,如果在引用表中存在相关的行,则操作不能执行!

【级联操作】

    可以在外键定义中将ON DELETE和ON UPDATE选项定义为:

CASCADE : 操作(更新和删除)将被级联到引用表中相关的行。

SET DEFAULT : 补偿操作将会把相关行的外键属性设置为列的默认值。

SET NULL : 补偿操作将会把相关行的外键属性设置为NULL值。

posted @ 2010-01-25 14:16 张念 阅读(222) 评论(0) 编辑

2010年1月19日

数据加密和解密

1   数据加密和解密

1.1  典型场合

    在使用加密的典型场合中,双方(Alice 和 Bob)在不安全的信道上通信。Alice 和 Bob 想要确保任何可能正在侦听的人无法理解他们之间的通信。而且,由于 Alice 和 Bob 相距遥远,因此 Alice 必须确保她从 Bob 处接受到的信息没有在传输期间被任何人修改。此外,她必须确保信息确实是来自 Bob,而不是来自模仿 Bob 的人。

     加密通常用于达到以下目的:

    (1)保密性:帮助保护用户的标识或数据不被读取。

    (2)数据完整性:帮助保护数据不被更改。

    (3)身份验证:确保数据发自特定的一方。

(4)不可否认性(不可抵赖性):防止特定的一方否认发送过消息。

1.2  私钥加密(对称加密)

    私钥加密算法使用单个私钥来加密和解密数据。由于具有密钥的任意一方都可以使用该密钥解密您的数据,或加密他们自己的数据并声称该数据源自您,因此必须保护密钥不被未经授权的代理得到。

    私钥加密又称为对称加密,因为同一密钥既用于加密又用于解密。私钥加密算法的速度非常快(与公钥算法相比),它特别适用于对较大的数据流执行加密转换。从数学角度而言,公钥加密算法(例如 RSA)在可加密的数据量方面存在限制。私钥加密算法一般则没有这些问题。

    假定 Alice 和 Bob 是希望在非安全信道上通信的双方,他们可以按如下方式使用私钥加密:Alice 和 Bob 同意对特定的密钥和 IV 应用一种特定的算法(例如 AES)。Alice 撰写一条消息并创建要在其上发送该消息的网络流(可能是一个命名管道或网络电子邮件)。接下来,她使用该密钥和 IV 加密文本,并通过 Intranet 向 Bob 发送该加密消息和 IV。Bob 在收到该加密文本后,可使用 IV 和预先商定的密钥对它进行解密。即使传输的内容被人截获,截获者也无法恢复原始消息,因为他并不知道密钥。在此方案中,只有密钥必须保密。

    .NET Framework 提供了以下类来实现私钥加密算法:

    (1)AesManaged(在 .NET Framework 3.5 版中引入)

(2)DESCryptoServiceProvider

(3)HMACSHA1(从技术上讲,这是一种私钥算法,因为它表示结合使用加密哈希     函数和私钥计算的消息身份验证代码。)

(4)RC2CryptoServiceProvider

(5)RijndaelManaged

(6)TripleDESCryptoServiceProvider

 

 SymmetricAlgorithm表示所有对称算法的实现都必须从中继承的抽象基类,从 SymmetricAlgorithm 类派生的类使用一种称为密码块链接 (CBC) 的链接模式,该模式需要密钥 (Key) 和初始化向量 (IV) 才能执行数据的加密转换。若要解密使用其中一个 SymmetricAlgorithm 类加密的数据,必须将 Key 属性和 IV 属性设置为用于加密的相同值。为了保证对称算法有效,必须只有发送方和接收方知道密钥。

每当您创建其中一个 SymmetricAlgorithm 类的新实例时,或者当您手动调用 GenerateIV 方法时,IV 属性均自动设置为新的随机值。IV 属性的大小必须与 BlockSize 属性的大小相同。

    对于给定的密钥 k,不使用初始化向量的简单块密码将同一个纯文本输入块加密为同一个密码文本输出块。如果您的纯文本流中有重复块,则您的密码文本流中也会有重复块。如果未经授权的用户知道了您的纯文本块结构的任何信息,他们就可以利用该信息来解密已知的密码文本块,并有可能重新获得您的密钥。为了防止这个问题,前一个块中的信息被混合到下一个块的加密过程中。这样一来,两个相同的纯文本块的输出就变得不一样了。由于此技术使用前一个块加密下一个块,因此需要初始化向量来加密数据的第一个块。

1.2.1  DES加密算法

示例 1:

    下面的示例使用 DESCryptoServiceProvider 类将一些数据加密到内存,然后解密数据

 public static byte[] Encrypt(string plainText,SymmetricAlgorithm key)

 {

            MemoryStream ms = new MemoryStream();

            CryptoStream cs = new CryptoStream(ms, key.CreateEncryptor(), CryptoStreamMode.Write);

            StreamWriter sw = new StreamWriter(cs);

 

            sw.WriteLine(plainText);

 

            sw.Close();

            cs.Close();

            byte[] buffer = ms.ToArray();

            ms.Close();

            return buffer;

 }

 

   public static string Decrypt(byte[] buffer ,  SymmetricAlgorithm  key)

   {

            MemoryStream ms  =  new MemoryStream(buffer);

            CryptoStream cs = new CryptoStream(ms, key.CreateDecryptor(), CryptoStreamMode.Read);

            StreamReader reader = new StreamReader(cs);

            string plainText = reader.ReadLine();

            reader.Close();

            cs.Close();

            ms.Close();

            return plainText;

}

 

public static void Main()

{

            SymmetricAlgorithm key = new DESCryptoServiceProvider();

            key.Key = Encoding.Default.GetBytes("12345678");

            key.IV = Encoding.Default.GetBytes("12345678");

            byte[] bytes = Encrypt("plain text", key);

            string plaintText = Decrypt(bytes, key);

 }

 

 

 

项目实例  

    DES文件加密解密演示程序

 

 

private void EncryptData(string finName,string foutName,byte[] key,byte[] iv)

 {

            FileStream fin = new FileStream(finName, FileMode.Open, FileAccess.Read);

            byte[] buffer = new byte[fin.Length];

 

            fin.Read(buffer, 0, buffer.Length);

            fin.Flush();

            fin.Close();

 

            MemoryStream ms = new MemoryStream();

            DESCryptoServiceProvider des = new DESCryptoServiceProvider ();

            CryptoStream cs = new CryptoStream(ms,des.CreateEncryptor(key,iv),CryptoStreamMode.Write);

 

            cs.Write(buffer, 0, buffer.Length);

            cs.FlushFinalBlock();

 

            byte[] array = ms.ToArray();

 

            FileStream fout = new FileStream(foutName,FileMode.OpenOrCreate,FileAccess.Write);

            fout.Write(array, 0, array.Length);

            fout.Flush();

            fout.Close();

}

 

 private void DecryptData(string finName, string foutName, byte[] key, byte[] iv)

 {

            FileStream fin = new FileStream(finName, FileMode.Open, FileAccess.Read);

 

            byte[] buffer = new byte[fin.Length];

            fin.Read(buffer, 0, buffer.Length);

            fin.Flush();

            fin.Close();

 

            DESCryptoServiceProvider des = new DESCryptoServiceProvider();

            MemoryStream ms = new MemoryStream();

            CryptoStream cs = new CryptoStream(ms,des.CreateDecryptor(key,iv),CryptoStreamMode.Write);

            cs.Write(buffer,0,buffer.Length);

            cs.FlushFinalBlock();

 

            byte[] plaintArray = ms.ToArray();

 

            FileStream fout = new FileStream(foutName, FileMode.OpenOrCreate, FileAccess.Write);

            fout.Write(plaintArray, 0, plaintArray.Length);

            fout.Flush();

            fout.Close();

  }

 

项目实例2

DES字符串加密解密演示程序

 

private string Encrypt(string plainText, byte[] key, byte[] iv)

 {

            byte[] plaintArray = Encoding.UTF8.GetBytes(plainText);

            try

            {

                using (DESCryptoServiceProvider des = new DESCryptoServiceProvider())

                {

                    MemoryStream ms = new MemoryStream();

                    CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(key, iv), CryptoStreamMode.Write);

                    cs.Write(plaintArray, 0, plaintArray.Length);

                    cs.FlushFinalBlock();

 

                    byte[] buffer = ms.ToArray();

                    return Convert.ToBase64String(buffer);

                }

            }

                catch(Exception ex)

            {

 MessageBox.Show(ex.Message);

                return String.Empty;

            }

 }

 

 

private string Decrypt(string str, byte[] key, byte[] iv)

 {

            byte[] buffer = Convert.FromBase64String(str);

            try

            {

                using (DESCryptoServiceProvider des = new DESCryptoServiceProvider())

                {

                    MemoryStream ms = new MemoryStream();

                    CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(key, iv), CryptoStreamMode.Write);

                    cs.Write(buffer, 0, buffer.Length);

                    cs.FlushFinalBlock();

 

                    byte[] plainArray = ms.ToArray();

 

                    return Encoding.UTF8.GetString(plainArray,0,plainArray.Length);

                }

            }

            catch(Exception ex)

            {

                MessageBox.Show(ex.Message);

                return String.Empty;

            }

        }

 

演示如下:

 

posted @ 2010-01-19 01:06 张念 阅读(183) 评论(0) 编辑

<2012年2月>
2930311234
567891011
12131415161718
19202122232425
26272829123
45678910

导航

统计

公告

昵称:张念
园龄:3年6个月
粉丝:2
关注:0

搜索

 

常用链接

我的标签

随笔档案

最新评论

阅读排行榜

评论排行榜

推荐排行榜