2008年10月21日星期二

c#2.0泛型学习

根据微软的视频教程"跟我一起学Visual Studio 2005C#语法篇"来学,因为里面有比较多的代码示例,学起来比较容易好理解

1.未使用泛型的Stack类

1using System;
2
3public class Stack
4{
5 readonly int m_Size;
6 int m_StackPointer = 0;
7 object[] m_Items;
8 public Stack(): this(100)
9 { }
10 public Stack(int size)
11 {
12 m_Size = size;
13 m_Items = new object[m_Size];
14 }
15 public void Push(object item)
16 {
17 if (m_StackPointer >= m_Size)
18 throw new StackOverflowException();
19
20 m_Items[m_StackPointer] = item;
21 m_StackPointer++;
22 }
23 public object Pop()
24 {
25 m_StackPointer--;
26 if (m_StackPointer >= 0)
27 {
28 return m_Items[m_StackPointer];
29 }
30 else
31 {
32 m_StackPointer = 0;
33 throw new InvalidOperationException("Cannot pop an empty stack");
34 }
35 }
36}
37
2.使用泛型的类


1using System;
2
3public class Stack
4{
5 readonly int m_Size;
6 int m_StackPointer = 0;
7 T[] m_Items;
8 public Stack()
9 : this(100)
10 {
11 }
12 public Stack(int size)
13 {
14 m_Size = size;
15 m_Items = new T[m_Size];
16 }
17 public void Push(T item)
18 {
19 if (m_StackPointer >= m_Size)
20 throw new StackOverflowException();
21
22 m_Items[m_StackPointer] = item;
23 m_StackPointer++;
24 }
25 public T Pop()
26 {
27 m_StackPointer--;
28 if (m_StackPointer >= 0)
29 {
30 return m_Items[m_StackPointer];
31 }
32 else
33 {
34 m_StackPointer = 0;
35 //throw new InvalidOperationException("Cannot pop an empty stack");
36 return default(T);
37 }
38 }
39}
40
41public class Stack1 : Stack
42{
43
44}
45
下为PDF文档,我感觉挺好的,很简单,我听的懂就是好的
/Clingingboy/one.pdf

多个泛型
1class Node
2{
3 public K Key;
4 public T Item;
5 public Node NextNode;
6 public Node()
7 {
8 Key = default(K);
9 Item = default(T);
10 NextNode = null;
11 }
12 public Node(K key, T item, Node nextNode)
13 {
14 Key = key;
15 Item = item;
16 NextNode = nextNode;
17 }
18}
泛型别名

1using list = LinkedList;
泛型约束

1public class LinkedList where K : IComparable
2{
3 Node m_Head;
4 public LinkedList()
5 {
6 m_Head = new Node();
7 }
8 public void AddHead(K key, T item)
9 {
10 Node newNode = new Node(key, item, m_Head.NextNode);
11 m_Head.NextNode = newNode;
12 }
13
14 T Find(K key)
15 {
16 Node current = m_Head;
17 while (current.NextNode != null)
18 {
19 if (current.Key.CompareTo(key) == 0)
20 break;
21 else
22 current = current.NextNode;
23 }
24 return current.Item;
25 }
26
27}
28

1using System;
2using System.Collections.Generic;
3using System.Text;
4
5namespace VS2005Demo1
6{
7 public class MyBaseClassGeneric // sealed,static
8 {
9 }
10
11 interface IMyBaseInterface
12 {
13 void A();
14 }
15
16 internal class GenericClass where T : MyBaseClassGeneric,IMyBaseInterface
17 {
18
19 }
20
21 class GClass where K : MyBaseClassGeneric,IMyBaseInterface,new() where T : K
22 {
23
24 }
25
26 class GUClass where T : K where K : MyBaseClassGeneric,IMyBaseInterface, new()
27 {
28 GClass obj = new GClass();
29 }
30
31
32 不能将引用/值类型约束与基类约束一起使用,因为基类约束涉及到类#region 不能将引用/值类型约束与基类约束一起使用,因为基类约束涉及到类
33
34 //class A where T : struct,class
35 //{}
36
37 #endregion
38
39 不能使用结构和默认构造函数约束,因为默认构造函数约束也涉及到类#region 不能使用结构和默认构造函数约束,因为默认构造函数约束也涉及到类
40
41 //class A where T : struct,new()
42 //{}
43
44 #endregion
45
46 虽然您可以使用类和默认构造函数约束,但这样做没有任何价值#region 虽然您可以使用类和默认构造函数约束,但这样做没有任何价值
47
48 class A where T : new()
49 {
50 T obj = new T();
51 }
52
53 class TypeA
54 {
55 public TypeA() { }
56 }
57
58 class TestA
59 {
60 A obj = new A();
61 }
62
63 #endregion
64
65 可以将引用/值类型约束与接口约束组合起来,前提是引用/值类型约束出现在约束列表的开头#region 可以将引用/值类型约束与接口约束组合起来,前提是引用/值类型约束出现在约束列表的开头
66
67 class SClass where K : struct, IMyBaseInterface
68 { }
69
70 class CClass where K : class, IMyBaseInterface
71 { }
72
73 #endregion
74}
75

资料引用:http://www.knowsky.com/339311.html

C#编程--基础知识点

.NetFramework简介
.netframework运行于操作系统之上,提供良好的跨语言特性。
.netframework包含两个内容:公共语言运行时(CLR)和类库集(FCL)
MSIL微软中间语言。当编译.net支持的语言编写的代码的时候,输出的代码为MSIL
CLR又包含:通用语言规范(CLS:保证语言互操作性的一组规则)和公共类型系统(CTS:包含了.net支持的各语言间兼容的数据类型和功能)

--------------------------------------------------------------------------------

C#中的变量和常量
C#中的基本数据类型:
值类型和引用类型
值类型:简单类型、结构类型和枚举类型。
简单类型:整数类型、浮点类型、小数类型(decimal)和布尔类型等
sbyte是有符号的,相当java的byte型,范围-128~127
C#中byte是无符号的,范围0~255

--------------------------------------------------------------------------------

变量命名方法:
帕斯卡命名法和骆驼命名法
帕斯卡命名法:如果有多个单词组成,每个单词首字母大写
骆驼命名法:如果有多个单词组成,第一个单词全部小写,后面的单词大写

--------------------------------------------------------------------------------

C#中的常量:const与readonly两种
const声明的常量:叫静态常量,必须声明时就初始化,且只能用常数值初始化
readonly声明的常量:叫动态常量,可以在声明时不初始化,只能在构造函数中初始化,但必须每个构造函数中都要初始化;而且可以使用变量值初始化

class Test
{
const float PI = 3.1416f; //常量命名:全部大写
readonly float G;
public Test()
{
G = 9.80F;
}
public Test(float g) //每个构造函数中都要初始化;而且可以使用变量值初始化
{
G = g;
}
}

--------------------------------------------------------------------------------

C#中的装箱和拆箱
装箱:值类型转换成有引用类型
拆箱:引用类型转换成值类型
值类型:存在栈中
引用类型:在堆中存放对象的地址(即引用),对象本身存放在栈中
拆装箱允许值类型和引用类型相互处理

--------------------------------------------------------------------------------

C#语法

Switch()括号中可以是int ,char和string ,switch语句中的case语句冒号后什么都不写,可以不写break,其他情况一定要写break,否则报错

数组:五种声明方式
int []array;
array = new int[2];

//第二种声明方式
int []array1 = new int[2];

//第三种声明方式
int []array2 = {1,2,3};

//第四种声明方式
int []array3 = new int[]{1,2,3};

//第五种声明方式
int []array4 = new int[3]{1,2,3};

//数组大小也可以是变量
int count = 3;
int []arr = new int[count];
--------------------------------------------------------------------------------

枚举:用有意义的字符去访问数据
public enum Contry:long //指定枚举类型,必须是整型,不写为int型
{
Pacific, //第一个未付值,默认为零
China=1860,
Japan,
US=1901,
Canada

}

--------------------------------------------------------------------------------

C#中的面向对象
析构函数:函数名与构造函数名一样,~函数名(),不接受参数,由垃圾回收器自动调用(GC.Collect()调用垃圾回收器)


virtual关键字:C#中,子类要重写父类的方法,必须把父类的方法标识为virtual(虚拟的),同时重写方法用override修饰
new 关键字:new关键字:在子类中定义的一个和父类方法签名一样,但是个全新的方法。并非重写父类的方法。
base关键字:用base关键字调用父类的方法

访问修饰符:
public 公有的,
internal 在一个项目中的,
protected有父子关系的类,
private仅所属类的成员

注意:如果有一个类既继承类又实现接口,类名要写在接口名前面。



--------------------------------------------------------------------------------

属性,索引器,委托,事件

属性:访问修饰一般为public,首字母大写。属性内有get和set访问器,get内必须要有return,set内有value关键字,代表从外部接受的值。
索引器:索引器的作用:像处理数组一样去处理类的对象。
public class Student
{
private string []obj=new string[10];

//this关键字在这里代表每一个类的对象,[]中整数是指通过下标访问
public string this[int index] //此是可以通过索引号去访问每一个类的成员
{
get
{
return obj[index];
}
set
{
if(value!=null)
obj[index]=value;
}
}
static void Main(string []args)
{
Student stucollection=new Student();
stucollection[0]="柯南";
stucollection[1]="小五郎";
stucollection[5]="怪盗基德";
}
}


委托:相当于函数指针,可使程序在运行是再指定具体要运行的方法。
(1) 定义委托:Public delegate int Call()
(2) 实例化委托:objcall=new Call(方法名)
(3) 调用委托:objcall();

事件:事件实际上是一种特殊的委托,委托每次只能指向一个方法,而事件可以指向多个方法
(1)定义一个委托public delegate void delegateMe();
(2)定义一个事件 private event delegate eventMe;
(3)订阅事件 eventMe+=new delegateMe(方法名1());
eventMe+=new delegateMe(方法名2());
(4) 引发事件 if(condition) then eventMe();



--------------------------------------------------------------------------------
多线程

创建线程实例:
Thread obj=new Thread(new ThreadStart(方法名称))
开始:Start();
休眠:Sleep();
终止:Abort();
挂起:Suspend();
恢复:Resume();
当前线程:Thread.CurrentThread
ThreadPriority枚举值用来指定调度线程的优先级(共5级)

lock关键字
C#中通过lock关键字提供同步
线程同步:确保不同的线程对共享资源进行访问时,每次只有一个线程访问资源。
Lock(this)
{
For(int i=0;i<10;i++)
{
//语句;
}
}



--------------------------------------------------------------------------------

数组集合对象

Array: Array和数组很相似,还可以相互转化和拷贝,很多方法都是是通用, 可以用Array的静态方法对数组实现反转,排序,这是数组本身无法做到的

using system.Array;
Array ar=Array.CreateInstance(typeof(int),5); //创建一个Array的实例
ar.SetValue(12,0); //赋值

Array.Reverse(ar); // 反转
Array.Sort(ar); // 排序

ArrayList:最常用的集合之一.集合的好处是在不知道数据大小时,可以实现容量自动增长,而数组做不到.
Add()添加元素
Remove(位置)移除元素

ArrayList al=new ArrayList();
//如果要遍历集合元素,
//方法一:
//将集合中的数拷贝到数组中
object []temp=al.ToArray();
foreach(object t in temp)
{
Console.WriteLine(t);
}

//方法二,使用迭代器
IEnumerator ie=al.GetEnumerator();
while(ie.MoveNext())
{
Console.WriteLine(ie.Current);
}

HashTable:以键值对的形式保存值

Hashtable hash=new Hashtable(4);
hash.Add("中国",1860);
hash.Add("德国",1940);

Console.WriteLine(hash["中国"].ToString());通过key获得value


SortedList :是 Hashtable 和 Array 的混合
能存放键值对,类似Hashtable
能通过自身提供的方法通过索引直接遍历,类似于Array
objsortlist.GetKey(i) 方法获得键
objsortlist.GetByIndex(i)方法获得值

.NET 2.0下读取数据库中的全部表以及表内的字段名

TDBOperator db = null;

try

{

db = TDBOperatorFactory.GetDBOperator(comFunction.getDBLink());

//打开数据库连接

db.Open();

System.Data.Common.DbConnection dc = db.getDbConnection();

string[] res = new string[4];

res[1] = "dbo";

//取得全部表名

DataTable dt = dc.GetSchema("Tables");

this.Text = dt.Rows.Count.ToString();

dt.WriteXml("table.xml");

foreach (System.Data.DataRow row in dt.Rows)

{

//取出数据库中系统表外的所有表名

if (row[3].ToString() == "TABLE")

{

listBox1.Items.Add(row[2].ToString());

listBox1.Items.Add("============================");

for (int i = 0; i < 4; i++) res[i] = null;

res[2] = row[2].ToString();

//取得相应表的所有字段

DataTable dtColumns = dc.GetSchema("Columns", res);

foreach (System.Data.DataRow rowColumns in dtColumns.Rows)

{

listBox1.Items.Add(rowColumns[3].ToString());

}

dtColumns.WriteXml(row[2].ToString() + "b.xml");

listBox1.Items.Add("============================");

}

}

}

catch (Exception ex)

{

comMsgBox.showError(ex.Message);

}

finally

{

db.Close();

}

C#通过ADO.NET建表点实现方法

新建表:
create table [表名]
(
[自动编号字段] int IDENTITY (1,1) PRIMARY KEY ,
[字段1] nVarChar(50) default '默认值' null ,
[字段2] ntext null ,
[字段3] datetime,
[字段4] money null ,
[字段5] int default 0,
[字段6] Decimal (12,4) default 0,
[字段7] image null ,
)

删除表:
Drop table [表名]

插入数据:
INSERT INTO [表名] (字段1,字段2) VALUES (100,'abc.NET')

删除数据:
DELETE FROM [表名] WHERE [字段名]>100

更新数据:
UPDATE [表名] SET [字段1] = 200,[字段2] = 'abc.NET' WHERE [字段三] = 'HAIWA'

新增字段:
ALTER TABLE [表名] ADD [字段名] NVARCHAR (50) NULL

删除字段:
ALTER TABLE [表名] DROP COLUMN [字段名]

修改字段:
ALTER TABLE [表名] ALTER COLUMN [字段名] NVARCHAR (50) NULL

重命名表:(Access 重命名表,请参考文章:在Access数据库中重命名表)
sp_rename '表名', '新表名', 'OBJECT'

新建约束:
ALTER TABLE [表名] ADD CONSTRAINT 约束名 CHECK ([约束字段] <= '2000-1-1')

删除约束:
ALTER TABLE [表名] DROP CONSTRAINT 约束名

新建默认值
ALTER TABLE [表名] ADD CONSTRAINT 默认值名 DEFAULT 'abc.NET' FOR [字段名]

删除默认值
ALTER TABLE [表名] DROP CONSTRAINT 默认值名

汉字转换为拼音的函数收藏

using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace SplitWord
{
/**//**//**//// 用C#实现汉字转化为拼音
/// 实现的原理就是先将汉字转化成为内码,然后通过内码和拼音的对照来查找。
public class chs2py
{
/**//**//**//**/
/**//**//**//**/
/**//**//**//**/
/**//**//**////
///将汉字转换成为拼音
///作者:
///完成于:
///

static Regex MyRegex = new Regex("^[一-龥]$"); //汉字的正则表达式.eg: if(MyRegex.IsMatch(chrstr.ToString()))
private static int[] pyvalue = new int[]{-20319,-20317,-20304,-20295,-20292,-20283,-20265,-20257,-20242,-20230,-20051,-20036,-20032,-20026,
-20002,-19990,-19986,-19982,-19976,-19805,-19784,-19775,-19774,-19763,-19756,-19751,-19746,-19741,-19739,-19728,
-19725,-19715,-19540,-19531,-19525,-19515,-19500,-19484,-19479,-19467,-19289,-19288,-19281,-19275,-19270,-19263,
-19261,-19249,-19243,-19242,-19238,-19235,-19227,-19224,-19218,-19212,-19038,-19023,-19018,-19006,-19003,-18996,
-18977,-18961,-18952,-18783,-18774,-18773,-18763,-18756,-18741,-18735,-18731,-18722,-18710,-18697,-18696,-18526,
-18518,-18501,-18490,-18478,-18463,-18448,-18447,-18446,-18239,-18237,-18231,-18220,-18211,-18201,-18184,-18183,
-18181,-18012,-17997,-17988,-17970,-17964,-17961,-17950,-17947,-17931,-17928,-17922,-17759,-17752,-17733,-17730,
-17721,-17703,-17701,-17697,-17692,-17683,-17676,-17496,-17487,-17482,-17468,-17454,-17433,-17427,-17417,-17202,
-17185,-16983,-16970,-16942,-16915,-16733,-16708,-16706,-16689,-16664,-16657,-16647,-16474,-16470,-16465,-16459,
-16452,-16448,-16433,-16429,-16427,-16423,-16419,-16412,-16407,-16403,-16401,-16393,-16220,-16216,-16212,-16205,
-16202,-16187,-16180,-16171,-16169,-16158,-16155,-15959,-15958,-15944,-15933,-15920,-15915,-15903,-15889,-15878,
-15707,-15701,-15681,-15667,-15661,-15659,-15652,-15640,-15631,-15625,-15454,-15448,-15436,-15435,-15419,-15416,
-15408,-15394,-15385,-15377,-15375,-15369,-15363,-15362,-15183,-15180,-15165,-15158,-15153,-15150,-15149,-15144,
-15143,-15141,-15140,-15139,-15128,-15121,-15119,-15117,-15110,-15109,-14941,-14937,-14933,-14930,-14929,-14928,
-14926,-14922,-14921,-14914,-14908,-14902,-14894,-14889,-14882,-14873,-14871,-14857,-14678,-14674,-14670,-14668,
-14663,-14654,-14645,-14630,-14594,-14429,-14407,-14399,-14384,-14379,-14368,-14355,-14353,-14345,-14170,-14159,
-14151,-14149,-14145,-14140,-14137,-14135,-14125,-14123,-14122,-14112,-14109,-14099,-14097,-14094,-14092,-14090,
-14087,-14083,-13917,-13914,-13910,-13907,-13906,-13905,-13896,-13894,-13878,-13870,-13859,-13847,-13831,-13658,
-13611,-13601,-13406,-13404,-13400,-13398,-13395,-13391,-13387,-13383,-13367,-13359,-13356,-13343,-13340,-13329,
-13326,-13318,-13147,-13138,-13120,-13107,-13096,-13095,-13091,-13076,-13068,-13063,-13060,-12888,-12875,-12871,
-12860,-12858,-12852,-12849,-12838,-12831,-12829,-12812,-12802,-12607,-12597,-12594,-12585,-12556,-12359,-12346,
-12320,-12300,-12120,-12099,-12089,-12074,-12067,-12058,-12039,-11867,-11861,-11847,-11831,-11798,-11781,-11604,
-11589,-11536,-11358,-11340,-11339,-11324,-11303,-11097,-11077,-11067,-11055,-11052,-11045,-11041,-11038,-11024,
-11020,-11019,-11018,-11014,-10838,-10832,-10815,-10800,-10790,-10780,-10764,-10587,-10544,-10533,-10519,-10331,
-10329,-10328,-10322,-10315,-10309,-10307,-10296,-10281,-10274,-10270,-10262,-10260,-10256,-10254};
private static string[] pystr = new string[]{"a","ai","an","ang","ao","ba","bai","ban","bang","bao","bei","ben","beng","bi","bian","biao",
"bie","bin","bing","bo","bu","ca","cai","can","cang","cao","ce","ceng","cha","chai","chan","chang","chao","che","chen",
"cheng","chi","chong","chou","chu","chuai","chuan","chuang","chui","chun","chuo","ci","cong","cou","cu","cuan","cui",
"cun","cuo","da","dai","dan","dang","dao","de","deng","di","dian","diao","die","ding","diu","dong","dou","du","duan",
"dui","dun","duo","e","en","er","fa","fan","fang","fei","fen","feng","fo","fou","fu","ga","gai","gan","gang","gao",
"ge","gei","gen","geng","gong","gou","gu","gua","guai","guan","guang","gui","gun","guo","ha","hai","han","hang",
"hao","he","hei","hen","heng","hong","hou","hu","hua","huai","huan","huang","hui","hun","huo","ji","jia","jian",
"jiang","jiao","jie","jin","jing","jiong","jiu","ju","juan","jue","jun","ka","kai","kan","kang","kao","ke","ken",
"keng","kong","kou","ku","kua","kuai","kuan","kuang","kui","kun","kuo","la","lai","lan","lang","lao","le","lei",
"leng","li","lia","lian","liang","liao","lie","lin","ling","liu","long","lou","lu","lv","luan","lue","lun","luo",
"ma","mai","man","mang","mao","me","mei","men","meng","mi","mian","miao","mie","min","ming","miu","mo","mou","mu",
"na","nai","nan","nang","nao","ne","nei","nen","neng","ni","nian","niang","niao","nie","nin","ning","niu","nong",
"nu","nv","nuan","nue","nuo","o","ou","pa","pai","pan","pang","pao","pei","pen","peng","pi","pian","piao","pie",
"pin","ping","po","pu","qi","qia","qian","qiang","qiao","qie","qin","qing","qiong","qiu","qu","quan","que","qun",
"ran","rang","rao","re","ren","reng","ri","rong","rou","ru","ruan","rui","run","ruo","sa","sai","san","sang",
"sao","se","sen","seng","sha","shai","shan","shang","shao","she","shen","sheng","shi","shou","shu","shua",
"shuai","shuan","shuang","shui","shun","shuo","si","song","sou","su","suan","sui","sun","suo","ta","tai",
"tan","tang","tao","te","teng","ti","tian","tiao","tie","ting","tong","tou","tu","tuan","tui","tun","tuo",
"wa","wai","wan","wang","wei","wen","weng","wo","wu","xi","xia","xian","xiang","xiao","xie","xin","xing",
"xiong","xiu","xu","xuan","xue","xun","ya","yan","yang","yao","ye","yi","yin","ying","yo","yong","you",
"yu","yuan","yue","yun","za","zai","zan","zang","zao","ze","zei","zen","zeng","zha","zhai","zhan","zhang",
"zhao","zhe","zhen","zheng","zhi","zhong","zhou","zhu","zhua","zhuai","zhuan","zhuang","zhui","zhun","zhuo",
"zi","zong","zou","zu","zuan","zui","zun","zuo"};
/**//**//**////
/// 转化汉字的全部拼音
///

///
///
public static string Convert(string chrstr)
{
Regex MyRegex = new Regex("^[一-龥]$");
byte[] array = new byte[2];
string returnstr = "";
int chrasc = 0;
int i1 = 0;
int i2 = 0;
char[] nowchar = chrstr.ToCharArray();
for (int j = 0; j < nowchar.Length; j++)
{
if (MyRegex.IsMatch(nowchar[j].ToString()))
{
array = System.Text.Encoding.Default.GetBytes(nowchar[j].ToString());
i1 = (short)(array[0]);
i2 = (short)(array[1]);
chrasc = i1 * 256 + i2 - 65536;
if (chrasc > 0 && chrasc < 160)
{
returnstr += nowchar[j];
}
else
{
for (int i = (pyvalue.Length - 1); i >= 0; i--)
{
if (pyvalue[i] <= chrasc)
{
returnstr += pystr[i];
break;
}
}
}
}
else
{
returnstr += nowchar[j].ToString();
}
}
return returnstr;
}
//ChineseToPY
/**//**//**////
/// 只转换汉字首字母
///

///
///
public static string GetChineseSpell(string strText)
{
int len = strText.Length;
string myStr = "";
for (int i = 0; i < len; i++)
{
myStr += getSpell(strText.Substring(i, 1));
}
return myStr;
}


public static string getSpell(string cnChar)
{
byte[] arrCN = Encoding.Default.GetBytes(cnChar);
if (arrCN.Length > 1)
{
int area = (short)arrCN[0];
int pos = (short)arrCN[1];
int code = (area << 8) + pos;
int[] areacode ={ 45217, 45253, 45761, 46318, 46826, 47010, 47297, 47614, 48119, 48119, 49062, 49324, 49896, 50371, 50614, 50622, 50906, 51387, 51446, 52218, 52698, 52698, 52698, 52980, 53689, 54481 };
for (int i = 0; i < 26; i++)
{
int max = 55290;
if (i != 25) max = areacode[i + 1];
if (areacode[i] <= code && code < max)
{
return Encoding.Default.GetString(new byte[]{ (byte)(65 + i) });
}
}
return "*";
}
else return cnChar;
}
}
}

关于.NET使用自定义XML做参数配置文件

WEB开发,尤其是大型项目的开发,其中不乏大名鼎鼎的CMS,XXMS,呵呵.
他们都有个共同的特点,那就是网站配置参数N多.
怎么设置好众多的参数配置,是在项目初期需要规划的一个重点.
总结这几年做WEB开发的一点点积累.个人认为以下方案是比较合理化的,对于以后参数的增加修改带来的一些问题可以得到一定的控制.同样适合WINFORM哈.

运行环境: .NET 2.0
在项目设计过程中,采用模块化设计,所以参数也得独立开,每个模块的参数配置单独存放与一个单独的XML文件中.
原理:利用XML的序列化与反序列化配合实体读取和保存参数设置到XML文件中.
先看XML结构
SystemInfo.xml



网站标题
SiteTitle
设置网站的标题
Text
博客园
^.*$
False


网站地址
SiteUrl
设置网站的地址
Text
http://www.cnblogs.com
^.*$
False


配置文件子节点结构
/**/'''
''' 配置文件结构
'''

'''

_
Public Class ItemClass Item

Private _ColsDisplay As UInt16
Private _isRequired As Boolean
Private _name As String
Private _title As String
Private _explain As String
Private _mode As String
Private _value As String
Private _pattern As String
Private _range As String
Private _rangeHint As String

/**/'''
''' 节点名称
'''

Public Property Name()Property Name() As String
Get
Return Me._name
End Get
Set(ByVal value As String)
Me._name = value
End Set
End Property

/**/'''
''' 节点标题
'''

Public Property Title()Property Title() As String
Get
Return Me._title
End Get
Set(ByVal value As String)
Me._title = value
End Set
End Property

/**/'''
''' 节点说明
'''

Public Property Explain()Property Explain() As String
Get
Return Me._explain
End Get
Set(ByVal value As String)
Me._explain = value
End Set
End Property

/**/'''
''' 节点值类型
'''

Public Property Mode()Property Mode() As String
Get
Return Me._mode
End Get
Set(ByVal value As String)
Me._mode = value
End Set
End Property

/**/'''
''' 节点值
'''

Public Property Value()Property Value() As String
Get
Return Me._value
End Get
Set(ByVal value As String)
Me._value = value
End Set
End Property

/**/'''
''' 限制格式
'''

Public Property Pattern()Property Pattern() As String
Get
Return Me._pattern
End Get
Set(ByVal value As String)
Me._pattern = value
End Set
End Property

/**/'''
''' 选择范围
'''

Public Property Range()Property Range() As String
Get
Return Me._range
End Get
Set(ByVal value As String)
Me._range = value
End Set
End Property

/**/'''
''' 选择范围标题
'''

Public Property RangeHint()Property RangeHint() As String
Get
Return Me._rangeHint
End Get
Set(ByVal value As String)
Me._rangeHint = value
End Set
End Property

/**/'''
''' 是否必需
'''

Public Property IsRequired()Property IsRequired() As Boolean
Get
Return Me._isRequired
End Get
Set(ByVal value As Boolean)
Me._isRequired = value
End Set
End Property

/**/'''
''' 列显示
'''

Public Property ColsDisplay()Property ColsDisplay() As UInt16
Get
Return Me._ColsDisplay
End Get
Set(ByVal value As UInt16)
Me._ColsDisplay = value
End Set
End Property

End Class
自定义配置文件实体
/**/'''
''' 自定义配置文件实体
'''

'''

_
Public Class ConfigsClass Configs

Private _SiteTitle As Item
Private _SiteUrl As Item

/**/'''
''' 网站标题
'''

Public Property SiteTitle()Property SiteTitle() As Item
Get
Return Me._SiteTitle
End Get
Set(ByVal value As Item)
Me._SiteTitle = value
End Set
End Property

/**/'''
''' 网站地址
'''

Public Property SiteUrl()Property SiteUrl() As Item
Get
Return Me._SiteUrl
End Get
Set(ByVal value As Item)
Me._SiteUrl = value
End Set
End Property

End Class
以下需引用
Imports System.Xml
Imports System.Xml.Serialization

序列化XML文件的读取
/**/'''
''' 读取序列化XML配置文件内容
'''

''' 类型
''' 配置文件地址,绝对地址
'''
'''
Public Shared Function Deserialize()Function Deserialize(ByVal Types As Type, ByVal FilePath As String) As Object
Dim Fs As FileStream = Nothing
Dim Xmls As Object = String.Empty
Fs = New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
Dim Xms As XmlSerializer = New XmlSerializer(Types)
Xmls = Xms.Deserialize(Fs)
Fs.Flush()
Fs.Close()
Return Xmls
End Function
XML文件保存
/**/'''
''' 保存序列化XML配置文件内容
'''

''' 类型
''' 实体
''' 配置文件地址,绝对地址
'''
Public Shared Sub SaveConfig()Sub SaveConfig(ByVal Types As Type, ByVal Info As Configs, ByVal FilePath As String)
Dim Fs As Stream = New FileStream(FilePath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)
Dim Xms As XmlSerializer = New XmlSerializer(Types)
Xms.Serialize(Fs, Info)
Fs.Flush()
Fs.Close()
End Sub
调用参数

Dim Info As Configs = New Configs
Info = Deserialize(GetType (Configs), "SystemInfo.Xml")
Response.write(Info.SiteTitle.Title)
Response.write(Info.SiteTitle.Value)

以上为全部代码

下面做简单说明
以前自己做项目的时候.只是运用到简单的序列化与反序列化,同样也是在CNBLOG先辈们的手迹中得到的解释.
在运用一段时间后发现很繁琐. 因为我只用到了一层结构.


博客园

虽然这样很简单明了.可是在实际开发中,不免存在一些问题,比如:
1、输入值的类型判断
2、输入值是否允许空
3、输入值是否符合指定类型
4、在做UI的时候还需要找到对应的控件,再写相关的说明文字。
等等。。很繁琐。

而新的代码。解决了这些问题,在使用中,只需要调用相应节点的值就OK了。在对于内容解释及类型控制上尤其方便。再也不需要因为更改一个参数的控制,而去在N个HTML代码中定位你的配置参数控件,然后再XXXXX。直接使用XML文件编辑器修改XML文件就OK啦。

小弟第一次发表,欢迎大家批评指正!

一种简便实效的配置文件读写方法

主要做法:

第一步,将配置信息做一个简单的类。

要点:因为要用到序列化,而且是用XmlSerializer来序列化,所以要存到文件的变量信息都要声明为Public,要序列化的类用修饰。

示例:一个连接数据库的配置信息

'配置信息

Public Class Item

'初始默认值

Public ID As Integer = 0

Public Server As String = "(Local)"

Public Database As String = "NorthWind"

Public Tusted As Boolean = True

Public User As String = ""

Public Password As String = ""

End Class

第二步:配置处理的类。

说明:这个类是通用的。用到别的配置,你只需修改上面的配置信息类就可以了。它实现了存档和读取的功能,并转化为配置信息对象,操作起来较为方便。你可以添加内容加密的处理。

Public Class Config

'默认ConnectionInfo的ID

Public ID As Integer

'必须是Public,XmlSerializer只对Pulbic变量作用

Public Items As Item()

Private m_Count As Integer = 0

'添加配置信息

Public Sub Add(ByVal ConnectionInfo As Item)

If ConnectionInfo Is Nothing Then Exit Sub

If m_Count > 0 Then

If Not Me.ConnectionInfo(ConnectionInfo.ID) Is Nothing Then

MsgBox(ID.ToString & "已存在")

Exit Sub

End If

End If

ReDim Preserve Me.Items(m_Count)

Me.Items(m_Count) = ConnectionInfo

m_Count += 1

End Sub

'取指定ID的配置信息

Public ReadOnly Property ConnectionInfo(ByVal ID As Integer) As Item

Get

Dim mItem As Item

Dim i As Integer

For i = 0 To m_Count - 1

If Me.Items(i).ID = ID Then

mItem = Me.Items(ID)

Exit For

End If

Next

Return mItem

End Get

End Property

'序列化并保存到指定文件

Public Sub SaveXmlFile(ByVal FileName As String)

If Me Is Nothing Then Exit Sub

Dim XmlWriter As New System.IO.StreamWriter(FileName, False)

XmlWriter.Write(SerializeClass.GetXML(Me))

XmlWriter.Close()

End Sub

'从指定文件读取反序列化转为对象

Public Function LoadXmlFile(ByVal FileName As String) As Config

Dim XmlReader As New System.IO.StreamReader(FileName, System.Text.Encoding.Default)

Dim mConfig As Config

mConfig = CType(SerializeClass.LoadXML(GetType(Config), XmlReader.ReadToEnd), Config)

XmlReader.Close()

mConfig.m_Count = mConfig.Items.Length

Return mConfig

End Function

End Class


就以上两步就可以了,下面这个类是用来序列化用的。

'这是用XmlSerializer序列化对象的类

Public Class SerializeClass

Public Shared Function GetXML(ByVal mObject As Object) As String

Dim oSerializer As New System.Xml.Serialization.XmlSerializer(mObject.GetType)

Dim oStringWriter As New System.IO.StringWriter

oSerializer.Serialize(oStringWriter, mObject)

Return oStringWriter.ToString

End Function

Public Shared Function LoadXML(ByVal mClass As Type, ByVal XML As String) As Object

Dim oSerializer As New System.Xml.Serialization.XmlSerializer(mClass)

Dim oStringReader As New System.IO.StringReader(XML)

Return oSerializer.Deserialize(oStringReader)

End Function

End Class


以下是使用方法示例:

'测试存配置文件

Private Sub TestSaveConfig()

Dim mConfig As Config = New Config

Dim mItem As Item

mItem = New Item

mConfig.Add(mItem)

mItem = New Item

With mItem

.ID = 1

.User = "Master"

.Password = "123456"

.Tusted = False

End With

mConfig.Add(mItem)

mConfig.SaveXmlFile(Application.StartupPath & "\Config.xml")

End Sub

'测试读配置文件

Private Sub TestLoadConfig()

Dim mConfig As Config = New Config

mConfig = mConfig.LoadXmlFile(Application.StartupPath & "\Config.xml")

'读取默认值的用户名

MsgBox(mConfig.Items(mConfig.ID).User)

'不妨修改一下配置

mConfig.ID = 1

mConfig.ConnectionInfo(0).Server = "Server"

mConfig.ConnectionInfo(1).Database = "Master"

'再存盘

mConfig.SaveXmlFile(Application.StartupPath & "\Config.xml")

End Sub

MS SQL数据类型及长度限制

可以定义用户定义的数据类型,其是系统提供的数据类型的别名。有关用户定义的数据类型的更多信息,请参见 sp_addtype 和创建用户定义的数据类型。
  当两个具有不同数据类型、排序规则、精度、小数位数或长度的表达式通过运算符进行组合时:
通过将数据类型的优先顺序规则应用到输入表达式的数据类型来确定所得值的数据类型。有关更多信息,请参见数据类型的优先顺序。


  如果结果数据类型为 char、varchar、text、nchar、nvarchar 或 ntext,则结果值的排序规则由排序规则的优先顺序规则决定。有关更多信息,请参见排序规则的优先顺序。


  结果的精度、小数位数及长度取决于输入表达式的精度、小数位数及长度。有关更多信息,请参见精度、小数位数和长度。
  SQL Server 为 SQL-92 兼容性提供了数据类型同义词。有关更多信息,请参见数据类型同义词。

精确数字

整数

bigint 从 -2^63 (-9223372036854775808) 到 2^63-1 (9223372036854775807) 的整型数据(所有数字)。

int 从 -2^31 (-2,147,483,648) 到 2^31 - 1 (2,147,483,647) 的整型数据(所有数字)。

smallint 从 -2^15 (-32,768) 到 2^15 - 1 (32,767) 的整数数据。

tinyint 从 0 到 255 的整数数据。

bit

bit 1 或 0 的整数数据。

decimal 和 numeric

decimal 从 -10^38 +1 到 10^38 –1 的固定精度和小数位的数字数据。

numeric 功能上等同于 decimal。


money 和 smallmoney

money 货币数据值介于 -2^63 (-922,337,203,685,477.5808) 与 2^63 -1 (+922,337,203,685,477.5807) 之间,精确到货币单位的千分之十。

smallmoney 货币数据值介于 -214,748.3648 与 +214,748.3647 之间,精确到货币单位的千分之十。


近似数字

float 从 -1.79E + 308 到 1.79E + 308 的浮点精度数字。

real 从 -3.40E + 38 到 3.40E + 38 的浮点精度数字。


datetime 和 smalldatetime

datetime 从 1753 年 1 月 1 日到 9999 年 12 月 31 日的日期和时间数据,精确到百分之三秒(或 3.33 毫秒)。

smalldatetime 从 1900 年 1 月 1 日到 2079 年 6 月 6 日的日期和时间数据,精确到分钟。


字符串

char 固定长度的非 Unicode 字符数据,最大长度为 8,000 个字符。

varchar 可变长度的非 Unicode 数据,最长为 8,000 个字符。

text 可变长度的非 Unicode 数据,最大长度为 2^31 - 1 (2,147,483,647) 个字符。

Unicode 字符串

nchar 固定长度的 Unicode 数据,最大长度为 4,000 个字符。

nvarchar 可变长度 Unicode 数据,其最大长度为 4,000 字符。sysname 是系统提供用户定义的数据类型,在功能上等同于 nvarchar(128),用于引用数据库对象名。

ntext 可变长度 Unicode 数据,其最大长度为 2^30 - 1 (1,073,741,823) 个字符。


二进制字符串

binary 固定长度的二进制数据,其最大长度为 8,000 个字节。
varbinary 可变长度的二进制数据,其最大长度为 8,000 个字节。
image 可变长度的二进制数据,其最大长度为 2^31 - 1 (2,147,483,647) 个字节。


其它数据类型

cursor 游标的引用。

sql_variant
一种存储 SQL Server 支持的各种数据类型(text、ntext、timestamp 和 sql_variant 除外)值的数据类型。

table
一种特殊的数据类型,存储供以后处理的结果集。

timestamp
数据库范围的唯一数字,每次更新行时也进行更新。

uniqueidentifier
全局唯一标识符 (GUID)。

C#实现USB接口的程序代码

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
USB usb;
usb = new UDisk();//插入U盘
usb.OutputFile();//从U盘读出文件
usb.InputFile();//往U盘写入文件
usb.Dispose();//拔出U盘
Console.WriteLine("");
usb = new MDisk();//插入移动硬盘
usb.OutputFile();//从移动硬盘读出文件
usb.InputFile();//往移动硬盘写入文件
usb.Dispose();//拔出移动硬盘
Console.WriteLine("");
usb = new MP4();//插入MP4
usb.OutputFile();//从MP4读出文件
usb.InputFile();//往MP4写入文件
usb.Dispose();//拔出MP4
Console.ReadKey();
}

//USB接口
public interface USB : IDisposable
{
void OutputFile();//读出文件
void InputFile();//写入文件
}

//U盘
public class UDisk : USB
{
public UDisk()
{
Console.WriteLine("U盘准备就绪...");
}
public void OutputFile()
{
Console.WriteLine("从U盘读出文件");
}
public void InputFile()
{
Console.WriteLine("往U盘写入文件");
}
public void Dispose()
{
Console.WriteLine("U盘已被拔出");
}
}

//移动硬盘
public class MDisk : USB
{
public MDisk()
{
Console.WriteLine("移动硬盘准备就绪...");
}
public void OutputFile()
{
Console.WriteLine("从移动硬盘读出文件");
}
public void InputFile()
{
Console.WriteLine("往移动硬盘写入文件");
}
public void Dispose()
{
Console.WriteLine("移动硬盘已被拔出");
}
}

//MP4
public class MP4 : USB
{
public MP4()
{
Console.WriteLine("MP4准备就绪...");
}
public void OutputFile()
{
Console.WriteLine("从MP4读出文件");
}
public void InputFile()
{
Console.WriteLine("往MP4写入文件");
}
public void Dispose()
{
Console.WriteLine("MP4已被拔出");
}
}
}
}

C#编程 忘记密码功能的实现方法

int result = user.GetBackPassword(LoginName.Text.Trim(), Question.Text.Trim(),
Answer.Text.Trim(), Email.Text);

if (result == 1)
{
Message.Text = "您的密码已发送,请到邮箱查收";
//user.ChangePassword(
}
else
{
Message.Text = "您的输入信息有误!";
}



public int GetBackPassword(string userName, string question, string answer, string email)
{
object m_DBNull = Convert.DBNull;
//获得新的随机密码
string newPassword = MakePassword(6);
//定义存储过程参数
SqlParameter[] para = {
new SqlParameter("@userName", userName),
new SqlParameter("@question", question),
new SqlParameter("@answer", answer),
new SqlParameter("@newPassword", newPassword),
new SqlParameter("@result", SqlDbType.Int, 8, ParameterDirection.Output,
true, 0, 0, "", DataRowVersion.Default, m_DBNull)
};

//执行存储过程
try
{
DAL.SQLHelper.ExecuteNonQuery(DAL.SQLHelper.CONN_STRING, CommandType.StoredProcedure,
"GetBackPwd", para);
}
catch
{
throw new Exception("邮件无法发送!");
}
//获得输出参数的值
int result = Convert.ToInt32(para[4].Value);
//如果密码保护资料填写正确
if (result == 1)
{
//从Web.config获取发信人地址、邮件标题、邮件用户名和密码以及SmtpServer
string sender = System.Configuration.ConfigurationSettings.AppSettings["mainSender"];
string title = System.Configuration.ConfigurationSettings.AppSettings["mailTitle"];
string mailUser = System.Configuration.ConfigurationSettings.AppSettings["mailUser"];
string mailPwd = System.Configuration.ConfigurationSettings.AppSettings["mailPwd"];
string smtpServer = System.Configuration.ConfigurationSettings.AppSettings["mailSmtpServer"];
//发信
try
{
Mail.CDOsendmail(sender, email, title, "您在eshop的密码已找回,新密码为"+newPassword
, mailUser, mailPwd, smtpServer);
}
catch(Exception ex)
{
throw new Exception(ex.Message);
}
}

return result;
}



//随机生成密码
private static string MakePassword(int pwdLength)
{
//声明要返回的字符串
string tmpstr = "";
//密码中包含的字符数组
string pwdchars="abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
//数组索引随机数
int iRandNum;
//随机数生成器
Random rnd = new Random();
for(int i=0;i {
//Random类的Next方法生成一个指定范围的随机数
iRandNum = rnd.Next(pwdchars.Length);
//tmpstr随机添加一个字符
tmpstr += pwdchars[iRandNum];
}
return tmpstr;
}



ALTER PROCEDURE GetBackPwd
@question nvarchar(50),
@answer nvarchar(50),
@userName nvarchar(50),
@newPassword nvarchar(50),
@result int output
AS
if exists (SELECT * FROM USERINFO WHERE USERNAME=@USERNAME AND QUESTION=@QUESTION
AND ANSWER=@ANSWER)
BEGIN
SET @RESULT = 1
UPDATE USERINFO
SET USERPWD = @newPassword
WHERE userName = @userName
END
ELSE
BEGIN
SET @RESULT = -1
END
GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO







用Visual C#制作新闻阅读器

一、弄清结构再动手

  要想轻松的抽取RSS信息,自然先要了解它的结构,所谓“知己知彼,百战不殆”嘛。

  1、RSS的结构

  我们先打开百度新闻一个RSS链接,如果你再多打开几个别的网站的RSS链接,会发现他们都有大致相同的结构。而我们在揭秘RSS(上)中为大家讲解的其实就是编成实现这样的一个XML文件。

  为了能够方便地对这样的XML文档进行处理,在本文里,我们使用C#作为开发的语言。

  分析整个RSS链接后,我们知道RSS大致的结构入图1。




  2、抽取的原理

  知道了结构,我们还要知道结构中各部分的含义。在图1中RSS节点表示当前是一个RSS文件,它由一个CHANNEL节点及其子节点组成,其中一些子节点提供关于频道本身的信息,比如title表示频道的名称(“百度互联网新闻”)。

  CHANNEL节点又包含多个ITEM子节点,而ITEM节点就是程序需要处理的部分,因为它对应着每条实际的新闻项信息, 每个ITEM节点又通过其子节点提供关于这条新闻的详细信息,比如title表示新闻的标题(“微软IM称王”),link对应新闻实际的链接。

  RSS具体规范可查看http://blogs.law.harvard.edu/tech/rss

  知道了这些后,要编程就不困难啦。我们只需提取并显示出CHANNEL和ITEM下的各条信息就可以了。现在来看看具体的实现方法吧。

  二.做个程序读新闻

  对RSS有一定了解后,我们开始编写程序。先还是需要一个最简单的界面。新建一个Win Form 工程,在Form上放置一个Label,一个文本框txtURL用来输入RSS链接(就是各网站RSS链接中包含的地址),一个按钮bnRead用来执行读取新闻, 一个TreeView树形控件treeRSS显示读出的新闻项。

  1、定义装载结构

  根据上面分析的RSS结构,我们首先来建立一个rss类,用它来装载RSS链接中CHANNEL和ITEM的各条信息。代码如下:

public class rss
{
 public struct Channel
 {
  public string Title;
  public Hashtable Items;
 }

 public struct Item
 {
  public string Title;
  public string Description;
  public string Link;
 }
}

  Channel结构将存储CHANNEL节点包含的所有子节点信息,其中Items成员字段是一个Hashtable集合,程序会将Item结构作为对象加入集合,用来存储Channel下的所有Item节点。这里我只读取了有限的几个节点,读者可以根据实际需要扩展整个结构定义。

  2、从RSS链接中获取新闻信息

  现在我们就可以开始编写读取函数,将抽取出的RSS信息放入上面设计好的结构中。

  C#提供了专门的类来访问XML, 使我们能够轻松地读出RSS的内容。代码如下:

XmlTextReader Reader = new XmlTextReader(URL);
XmlValidatingReader Valid = new XmlValidatingReader(Reader);
Valid.ValidationType = ValidationType.None;
XmlDocument xmlDoc= new XmlDocument();
xmlDoc.Load(Reader);

  使用XmlDocument类将txtURL中输入的RSS链接加载后,首先通过FoundChildNode函数,找到Channel节点。

private XmlNode FoundChildNode(XmlNode Node,string Name)
{
 XmlNode childlNode = null;
 for (int i=0;i < Node.ChildNodes.Count;i++)
 {
  if ( Node.ChildNodes[i].Name == Name && Node.ChildNodes[i].ChildNodes.Count > 0 )
  {
   childlNode = Node.ChildNodes[i];
   return childlNode;
  }
 }
 return childlNode;
}
XmlNode rssNode = FoundChildNode(xmlDoc,"rss");
XmlNode channelNode = FoundChildNode(rssNode,"channel");

  然后我们就可以遍历它的子节点,根据子节点的Name属性,读取我们需要的信息。

rss.Channel channel=new rss.Channel();
channel.Items=new Hashtable();
{
 switch ( channelNode.ChildNodes[i].Name )
 {
  case "title":
   {
    channel.Title = channelNode.ChildNodes[i].InnerText;
    break;
   }
  case "item":
   {
    rss.Item item=this.getRssItem(channelNode.ChildNodes[i]);
    channel.Items.Add(channel.Items.Count,item );
    break;
   }
 }
}

  如果发现是item子节点,就调用getRssItem函数,同样通过遍历子节点的方法,将其子节点内容填入Item结构中,然后再添加到Channel结构的Items集合中。因为本程序并不关心添加到集合的键值,只需要它是不重复的值,所以我传入了Count属性。

  3.将读出的信息显示在程序中

  将RSS内容读出后,就需要把信息展示给用户了。我们这里用的是基本的TreeView方法,通过遍历Channel结构的Items集合,将其标题添加到TreeView中。

private void ViewRss(rss.Channel channel)
{
 treeRss.BeginUpdate();
 treeRss.Nodes.Clear();
 TreeNode channelNode=treeRss.Nodes.Add(channel.Title );
 channelNode.Tag="";
 for (int i=0;i  {
  rss.Item item=(rss.Item)channel.Items[i];
  TreeNode itemNode=channelNode.Nodes.Add(item.Title );
  itemNode.Tag=item.Link;
 }
 treeRss.ExpandAll();
 treeRss.EndUpdate();
}

  同时我们还可以设置TreeView的每个子节点的Tag属性为它对应的链接。以便当选中子节点时就可以通过读取Tag属性访问具体的信息。

private void treeRss_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e)
{
 TreeNode itemNode=e.Node ;
 string URL=itemNode.Tag.ToString();
 if (URL.Length!=0)
  System.Diagnostics.Process.Start( URL);
}

  程序运行效果如图2。




  三.小结

  怎么样,一个简单的RSS新闻阅读器就按前面所说轻松完成了,容易吧。虽然它还有很多不足,但如果大家通过这个例子学会了抽取RSS链接信息的基本方法,那就足够了!

使用c#捕获windows的关机事件

在公司上班,下班时需要签退,而我呢隔三差五就会忘那么一次。怎么办呢,于是就想能不能捕获Windows的关机事件,做一个程序让它在关机的时候提醒我一下呢。

  非常幸运很容易就找到了Microsoft.Win32命名空间下面的SystemEvents类,他有一个静态的事件SessionEnding在系统注销或者关机时发生,此事件只有在winform的程序下有效,而在控制台程序下面无效,不能激发事件;还有一点我们必须在程序推出时将加上的事件移除掉,否则就容易造成内存溢出。

  关键代码如下:

以下是引用片段:
  using System;
  using System.Collections.Generic;
  using System.Windows.Forms;
  using Microsoft.Win32;
  namespace Shutdown
  {
  static class Program
  {
  /**////
  /// 应用程序的主入口点。
  ///
  [STAThread]
  static void Main()
  {
  Application.EnableVisualStyles();
  Application.SetCompatibleTextRenderingDefault(false);
  FormShutdown formShutdown = new FormShutdown();
  SystemEvents.SessionEnding += new SessionEndingEventHandler(formShutdown.SystemEvents_SessionEnding);
  Application.Run(formShutdown);
  }
  }
  }Form 的代码:
  using System;
  using System.Collections.Generic;
  using System.ComponentModel;
  using System.Data;
  using System.Drawing;
  using System.Text;
  using System.Windows.Forms;
  using Microsoft.Win32;
  namespace Shutdown
  {
  public partial class FormShutdown : Form
  {
  const string MESSAGE_TXT = "您签退了吗?";
  const string MESSAGE_TITLE = "提示";
  public FormShutdown()
  {
  InitializeComponent();
  }
  internal void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e)
  {
  DialogResult result = MessageBox.Show(MESSAGE_TXT, MESSAGE_TITLE, MessageBoxButtons.YesNo);
  e.Cancel = (result == DialogResult.No);
  }
  private void FormShutdown_Load(object sender, EventArgs e)
  {
  this.Location = new Point(Screen.PrimaryScreen.WorkingArea.Width - 200, 0);
  }
  protected override void OnClosed(EventArgs e)
  {
  SystemEvents.SessionEnding -= new SessionEndingEventHandler(this.SystemEvents_SessionEnding);
  base.OnClosed(e);
  }
  }
  }



  此程序在使用C#2.0在Windows2003下测试通过。大家在使用SystemEvents.SessionEnding事件时切记要在程序退出时移除事件。

  不过有两点遗憾之处:

  1. 使用这种方式不能捕获休眠时的事件

  2. 这个程序占用的内存太多了,只有这么一个小功能居然占了12M的内存,这都是.net Framework惹的货;实在是不可思议。

  大家有没有什么好主意可以克服这两个缺点呢?

一个用C#过滤HTML代码的函数

public string checkStr(string html)
{
System.Text.RegularExpressions.Regex regex1 = new System.Text.RegularExpressions.Regex(@"", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex2 = new System.Text.RegularExpressions.Regex(@" href *= *[\s\S]*script *:", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex3 = new System.Text.RegularExpressions.Regex(@" no[\s\S]*=", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex4 = new System.Text.RegularExpressions.Regex(@"", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex5 = new System.Text.RegularExpressions.Regex(@"", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex6 = new System.Text.RegularExpressions.Regex(@"\]+\>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex7 = new System.Text.RegularExpressions.Regex(@"

", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex8 = new System.Text.RegularExpressions.Regex(@"

", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex9 = new System.Text.RegularExpressions.Regex(@"<[^>]*>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
html = regex1.Replace(html, ""); //过滤标记
html = regex2.Replace(html, ""); //过滤href=JavaScript: () 属性
html = regex3.Replace(html, " _disibledevent="); //过滤其它控件的on...事件
html = regex4.Replace(html, ""); //过滤iframe
html = regex5.Replace(html, ""); //过滤frameset
html = regex6.Replace(html, ""); //过滤frameset
html = regex7.Replace(html, ""); //过滤frameset
html = regex8.Replace(html, ""); //过滤frameset
html = regex9.Replace(html, "");
html = html.Replace(" ", "");
html = html.Replace("", "");
html = html.Replace("", "");
return html;
}

关于C#在lucene.net下的中文切词

经过一天的研究,终于完成了C#在lucene.net下可以使用的中文切词方法。感到有些复杂,不过我还是拿下了。颇有点成就感的,发上来跟大家分享一下!

  在实现了中文切词的基础方法上,我将其封装在继承lucene的Analyzer类下

  chineseAnalzer的方法就不用多说了。

以下是引用片段:
  using System;
  using System.Collections.Generic;
  using System.Text;
  
  using Lucene.Net.Analysis;
  using Lucene.Net.Analysis.Standard;
  
  namespace Lucene.Fanswo
  {
   /**////
   ///
   ///
   public class ChineseAnalyzer:Analyzer
   {
   //private System.Collections.Hashtable stopSet;
   public static readonly System.String[] CHINESE_ENGLISH_STOP_WORDS = new System.String[] { "a", "an", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "no", "not", "of", "on", "or", "s", "such", "t", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with", "我", "我们" };
  
  
   /**//// Constructs a {@link StandardTokenizer} filtered by a {@link
   /// StandardFilter}, a {@link LowerCaseFilter} and a {@link StopFilter}.
   ///
   public override TokenStream TokenStream(System.String fieldName, System.IO.TextReader reader)
   {
   TokenStream result = new ChineseTokenizer(reader);
   result = new StandardFilter(result);
   result = new LowerCaseFilter(result);
   result = new StopFilter(result, CHINESE_ENGLISH_STOP_WORDS);
   return result;
   }
  
   }
  }
  

  ChineseTokenizer类的实现:

  这里通过词典来正向匹配字符,返回lucene下定义的token流



以下是引用片段:
  using System;
  using System.Collections.Generic;
  using System.Text;
  using Lucene.Net.Analysis;
  using System.Collections;
  using System.Text.RegularExpressions;
  using System.IO;
  
  namespace Lucene.Fanswo
  {
   class ChineseTokenizer : Tokenizer
   {
  
   private int offset = 0, bufferIndex = 0, dataLen = 0;//偏移量,当前字符的位置,字符长度
  
   private int start;//开始位置
   /**////
   /// 存在字符内容
   ///
   private string text;
  
   /**////
   /// 切词所花费的时间
   ///
   public double TextSeg_Span = 0;
  
   /**//// Constructs a tokenizer for this Reader.
   public ChineseTokenizer(System.IO.TextReader reader)
   {
   this.input = reader;
   text = input.ReadToEnd();
   dataLen = text.Length;
   }
  
   /**//// 进行切词,返回数据流中下一个token或者数据流为空时返回null
   ///
   ///
   public override Token Next()
   {
   Token token = null;
   WordTree tree = new WordTree();
   //读取词库
   tree.LoadDict();
   //初始化词库,为树形
   Hashtable t_chartable = WordTree.chartable;
   string ReWord = "";
   string char_s;
   start = offset;
   bufferIndex = start;
  
   while (true)
   {
   //开始位置超过字符长度退出循环
   if (start >= dataLen)
   {
   break;
   }
   //获取一个词
   char_s = text.Substring(start, 1);
   if (string.IsNullOrEmpty(char_s.Trim()))
   {
   start++;
   continue;
   }
   //字符不在字典中
   if (!t_chartable.Contains(char_s))
   {
   if (ReWord == "")
   {
   int j = start + 1;
   switch (tree.GetCharType(char_s))
   {
   case 0://中文单词
   ReWord += char_s;
   break;
   case 1://英文单词
   j = start + 1;
   while (j < dataLen)
   {
   if (tree.GetCharType(text.Substring(j, 1)) != 1)
   break;
  
   j++;
   }
   ReWord += text.Substring(start, j - offset);
  
   break;
   case 2://数字
   j = start + 1;
   while (j < dataLen)
   {
   if (tree.GetCharType(text.Substring(j, 1)) != 2)
   break;
  
   j++;
   }
   ReWord += text.Substring(start, j - offset);
  
   break;
  
   default:
   ReWord += char_s;//其他字符单词
   break;
   }
  
   offset = j;//设置取下一个词的开始位置
   }
   else
   {
   offset = start;//设置取下一个词的开始位置
   }
  
   //返回token对象
   return new Token(ReWord, bufferIndex, bufferIndex + ReWord.Length - 1);
   }
   //字符在字典中
   ReWord += char_s;
   //取得属于当前字符的词典树
   t_chartable = (Hashtable)t_chartable[char_s];
   //设置下一循环取下一个词的开始位置
   start++;
   if (start == dataLen)
   {
   offset = dataLen;
   return new Token(ReWord, bufferIndex, bufferIndex + ReWord.Length - 1);
   }
   }
   return token;
   }
  
   }
  }


  测试的代码:

以下是引用片段:
  using System;
  using System.Collections.Generic;
  using System.Text;
  
  using Analyzer = Lucene.net.Analysis.Analyzer;
  using SimpleAnalyzer = Lucene.Net.Analysis.SimpleAnalyzer;
  using StandardAnalyzer = Lucene.Net.Analysis.Standard.StandardAnalyzer;
  using Token = Lucene.Net.Analysis.Token;
  using TokenStream = Lucene.Net.Analysis.TokenStream;
  
  namespace MyLuceneTest
  {
   class Program
   {
   [STAThread]
   public static void Main(System.String[] args)
   {
   try
   {
   Test("中华人民共和国在1949年建立,从此开始了新中国的伟大篇章。长春市长春节致词", true);
   }
   catch (System.Exception e)
   {
   System.Console.Out.WriteLine(" caught a " + e.GetType() + "\n with message: " + e.Message + e.ToString());
   }
   }
  
   internal static void Test(System.String text, bool verbose)
   {
   System.Console.Out.WriteLine(" Tokenizing string: " + text);
   Test(new System.IO.StringReader(text), verbose, text.Length);
   }
  
   internal static void Test(System.IO.TextReader reader, bool verbose, long bytes)
   {
   //Analyzer analyzer = new StandardAnalyzer();
   Analyzer analyzer = new Lucene.Fanswo.ChineseAnalyzer();
   TokenStream stream = analyzer.TokenStream(null, reader);
  
   System.DateTime start = System.DateTime.Now;
  
   int count = 0;
   for (Token t = stream.Next(); t != null; t = stream.Next())
   {
   if (verbose)
   {
   System.Console.Out.WriteLine("Token=" + t.ToString());
   }
   count++;
   }
  
   System.DateTime end = System.DateTime.Now;
  
   long time = end.Ticks - start.Ticks;
   System.Console.Out.WriteLine(time + " milliseconds to extract " + count + " tokens");
   System.Console.Out.WriteLine((time * 1000.0) / count + " microseconds/token");
   System.Console.Out.WriteLine((bytes * 1000.0 * 60.0 * 60.0) / (time * 1000000.0) + " megabytes/hour");
   }
   }
  }
  

  测试结果:


  

  完毕!

  分词的郊率上还有待在算法上提高。还有中文的标点符号没有处理,我将进一步完善。

  

详解Visual C#数据库编程

本文就来着重探讨一下Visual C#数据库基本编程,即:如何浏览记录、修改记录、删除记录和插入记录。针对数据库编程始终是程序设计语言的一个重要方面的内容,也是一个难点。数据库编程的内容十分丰富,但最为基本编程的也就是那么几点,譬如:连接数据库、得到需要的数据和针对数据记录的浏览、删除、修改、插入等操作。其中又以后面针对数据记录的数据操作为重点。

  一.程序设计和运行的环境设置:

  (1).视窗2000服务器版

  (2).Microsoft Data Acess Component 2.6 以上版本 ( MDAC 2.6 )

  (3)..net Framework SDK Beta 2

  为了更清楚的说明问题,在数据库的选用上,采用了当前比较典型的数据库,一个是本地数据库Access 2000,另外一个是远程数据库SQL Server 2000。其中本地数据库名称为"db.mdb",在其中定义了一张数据表"person","person"表的数据结构如下表:

  字段名称 字段类型 字段意思

  id 数字 序号

  xm 文本 姓名

  xb 文本 性别

  nl 文本 年龄

  zip 文本 邮政编码

  远程数据库Sql Server 2000的数据库服务器名称为"Server1",数据库名称为"Data1",登陆的ID为"sa",口令为空,在数据库也定义了一张"person"表,数据结构如上表。

  二.如何浏览数据:

  在《Visual C#的数据绑定》中,已经了解了如何把数据集中的某些字段绑定到WinForm组件的某个属性上,这样程序员就可以根据以WinForm组件的来定制数据显示的形式,并且此时的WinForm组件显示内容就可以随着记录指针的变化而改变。至此可见,浏览数据记录的关键就是如何改变记录指针。要实现这种操作,就要使用到BindingManagerBase类,此类的主要作用是管理对于那些实现了对同一个数据源进行绑定的对象。说的具体些,就是能够使得Windows窗体上的已经对同一数据源进行数据绑定的组件保持同步。在BindingManagerBase类中定义了一个属性"Position",通过这个属性就可以改变BindingManagerBase对象中的数据指针。创建BindingManagerBase对象必须要使用到BindingContext类,其实每一个由Control类中继承而得到的对象,都有单一的BindingContext对象,在大多数创建窗体中实现数据绑定组件的BindingManagerBase对象是使用Form类的BindingContext来得到。下列代码是以Access 2000数据库为模型,创建的一个名称为"myBind"的BindingManagerBase对象。

以下是引用片段:
  //创建一个 OleDbConnection
  string strCon = " Provider = Microsoft.Jet.OLEDB.4.0 ; Data Source = db.mdb" ;
  OleDbConnection myConn = new OleDbConnection ( strCon ) ;
  string strCom = " SELECT * FROM person " ;
  file://创建一个 DataSet
  myDataSet = new DataSet ( ) ;
  myConn.Open ( ) ;
  file://用 OleDbDataAdapter 得到一个数据集
  OleDbDataAdapter myCommand = new OleDbDataAdapter ( strCom , myConn ) ;
  file://把Dataset绑定books数据表
  myCommand.Fill ( myDataSet , "person" ) ;
  file://关闭此OleDbConnection
  myConn.Close ( ) ;
  myBind = this.BindingContext [ myDataSet , "person" ] ;


  下列代码是以Sql Server 2000数据库为模型,创建一个名称为"myBind"的BindingManagerBase对象。

以下是引用片段:
  // 设定数据连接字符串,此字符串的意思是打开Sql server数据库,服务器名称为server1,数据库为data1
  string strCon = "Provider = SQLOLEDB.1 ; Persist Security Info = False ; User ID = sa ; Initial Catalog = data1 ; Data Source = server1 " ;
  OleDbConnection myConn = new OleDbConnection ( strCon ) ;
  myConn.Open ( ) ;
  string strCom = " SELECT * FROM person " ;
  file://创建一个 DataSet
  myDataSet = new DataSet ( ) ;
  file://用 OleDbDataAdapter 得到一个数据集
  OleDbDataAdapter myCommand = new OleDbDataAdapter ( strCom , myConn ) ;
  file://把Dataset绑定person数据表
  myCommand.Fill ( myDataSet , " person " ) ;
  file://关闭此OleDbConnection
  myConn.Close ( ) ;
  myBind = this.BindingContext [ myDataSet , "person" ] ;


  得到了是同一数据源的BindingManagerBase对象,通过改变此对象的"Position"属性值,这样绑定数据的组件显示的数据就随之变化,从而实现导航数据记录。

  < I > .导航按钮"上一条"实现方法:

以下是引用片段:
  protected void GoPrevious ( object sender , System.EventArgs e )
  {
  if ( myBind.Position == 0 )
  MessageBox.Show ( "已经到了第一条记录!" , "信息提示!" , MessageBoxButtons.OK , MessageBoxIcon.Information ) ;
  else
  myBind.Position -= 1 ;
  }


  < II > . 导航按钮"下一条"实现方法:

以下是引用片段:
  protected void GoNext ( object sender , System.EventArgs e )
  {
  if ( myBind.Position == myBind.Count -1 )
  MessageBox.Show ( "已经到了最后一条记录!", "信息提示!" , MessageBoxButtons.OK , MessageBoxIcon.Information ) ;
  else
  myBind.Position += 1 ;
  }


  < III > . 导航按钮"至尾"实现方法:

以下是引用片段:
  protected void GoLast ( object sender , System.EventArgs e )
  {
  myBind.Position = myBind.Count - 1 ;
  }


  < IV > . 导航按钮"至首"实现方法:

以下是引用片段:
  protected void GoFirst ( object sender , System.EventArgs e )
  {
  myBind.Position = 0 ;
  }


  注释:"Count"是BindingManagerBase对象的另外一个重要的属性,是数据集记录的总数。

  三.实现删除记录:

  在对数据记录进行操作的时候,有二点必须十分清晰:

  其一:在对数据记录进行操作的时候,我想有一些程序员一定有这样一个疑惑,当对数据库服务器请求数据集的时候,就会产生"DataSet"对象,用以管理数据集,这样如果这些对数据库服务器的请求非常多,同样也就会产生很多的"DataSet"对象,达到一定时候必然会使得数据库服务器崩溃。这种想法是自然的,但和实际并不相符,因为"DataSet"对象并不是在服务器端产生的,而是在客户端产生的。所以面对众多的数据请求的时候对数据库服务器的影响并不十分太大。

  其二:记得在用Delphi编写三层数据模型的时候的,每一次对数据库的修改其实只是对第二层产生的数据集的修改,要真正修改数据库,还必须调用一个另外的方法。在用ADO.NET处理数据库的时候,虽然处理的直接对象是数据库,但此时"DataSet"对象中的内容并没有随之改变,而绑定的数据组件显示的数据又来源于"DataSet"对象,这样就会产生一个错觉,就是修改了的记录并没有修改掉,删除的记录并没有删除掉。所以对数据记录进行操作的时候,在修改数据库后,还要对"DataSet"对象进行必要的修改,这样才能保证"DataSet"对象和数据库内容一致、同步。下面代码是删除当前绑定组件显示的记录的程序代码,此代码是以Access 2000数据库为模板的:

以下是引用片段:
  protected void Delete_record ( object sender , System.EventArgs e )
  {
  DialogResult r = MessageBox.Show ( "是否删除当前记录!" , "删除当前记录!" , MessageBoxButtons.YesNo , MessageBoxIcon.Question ) ;
  int ss = ( int ) r ;
  if ( ss == 6 ) // 按动"确定"按钮
  {
  try{
  file://连接到一个数据库
  string strCon = " Provider = Microsoft.Jet.OLEDB.4.0 ; Data Source = db.mdb " ;
  OleDbConnection myConn = new OleDbConnection ( strCon ) ;
  myConn.Open ( ) ;
  string strDele = "DELETE FROM person WHERE id= " + t_id.Text ;
  OleDbCommand myCommand = new OleDbCommand ( strDele , myConn ) ;
  file://从数据库中删除指定记录
  myCommand.ExecuteNonQuery ( ) ;
  file://从DataSet中删除指定记录
  myDataSet.Tables [ "person" ] . Rows [ myBind.Position ] . Delete ( ) ;
  myDataSet.Tables [ "person" ] . AcceptChanges ( ) ;
  myConn.Close ( ) ;
  }
  catch ( Exception ed )
  {
  MessageBox.Show ( "删除记录错误信息: " + ed.ToString ( ) , "错误!" ) ;
  }
  }
  }

使用C#编写查询IP段功能的程序

本文将通过一个实例来向大家讲解如何使用C#来编写一个具备查询IP段功能的小程序。

  主要功能:查询一个IP所有的IP段.

  关键:从Byte数组到ulong的转换出来的数字和 IPAddress.Address 返回值的是不一样的.

以下是引用片段:
  using System;
  using System.Collections.Generic;
  using System.Text;
  using System.net;
  namespace IPUtility
  {
  class Program
  {
  static void Main(string[] args)
  {
  IPRangeManage irm = new IPRangeManage();
  irm.Add(new IPRange("石家庄", "219.148.24.0", "219.148.63.255"));
  irm.Add(new IPRange("石家庄", "222.222.0.0", "222.222.63.255"));
  irm.Add(new IPRange("唐山", "219.148.64.0", "219.148.79.255"));
  irm.Add(new IPRange("保定", "219.148.20.0", "219.148.23.255"));
  Console.WriteLine(irm.Search("219.148.56.3").Name);
  Console.ReadLine();
  }
  }
  public class IPRange
  {
  private string _Name = string.Empty;
  private ulong _BeginIP = 0;
  private ulong _EndIP = Int32.MaxValue;
  /**////
  /// IP段名称
  ///
  public string Name
  {
  get { return _Name; }
  set { _Name = value; }
  }
  /**////
  /// ?始IP
  ///
  public ulong BeginIP
  {
  get { return _BeginIP; }
  set { _BeginIP = value; }
  }
  /**////
  /// ?束IP
  ///
  public ulong EndIP
  {
  get { return _EndIP; }
  set { _EndIP = value; }
  }
  /**////
  /// 此IP段的范?
  ///
  public ulong Range
  {
  get
  {
  return EndIP - BeginIP;
  }
  }
  public IPRange(string name, string iPBegin, string ipEnd)
  {
  this.Name = name;
  this.BeginIP = IP2A(ipBegin);
  this.EndIP = IP2A(ipEnd);
  }
  public static ulong IP2A(string ip)
  {
  byte[] bytes = IPAddress.Parse(ip).GetAddressBytes();
  ulong ret = 0;
  foreach (byte b in bytes)
  {
  ret <<= 8;
  ret |= b;
  }
  return ret;
  }
  public static int Compare(IPRange x, IPRange y)
  {
  if(x.Range == y.Range)
  return 0;
  else if(x.Range > y.Range)
  return 1;
  else return -1;
  }
  }
  public class IPRangeManage
  {
  public IPRangeManage()
  { }
  private List< IPRange> _IPRangeList = new List< IPRange>();
  private bool _NeedSort = true;
  public void Add(IPRange ipRange)
  {
  _IPRangeList.Add(ipRange);
  _NeedSort = true;
  }
  private void Sort()
  {
  if (_NeedSort)
  {
  _IPRangeList.Sort(new Comparison(IPRange.Compare));
  }
  }
  public IPRange Search(string ipString)
  {
  ulong ip = IPRange.IP2A(ipString);
  this.Sort();
  foreach (IPRange ir in _IPRangeList)
  {
  if (ir.BeginIP <= ip && ir.EndIP >= ip)
  {
  return ir;
  }
  }
  return null;
  }
  }
  }


  完毕。

C# 中的常用正则表达式总结

这是我发了不少时间整理的C#的正则表达式,新手朋友注意一定要手册一下哦,这样可以节省很多写代码的时间,中国自学编程网为新手朋友整理发布。

  只能输入数字:"^[0-9]*$"。

  只能输入n位的数字:"^\d{n}$"。

  只能输入至少n位的数字:"^\d{n,}$"。

  只能输入m~n位的数字:。"^\d{m,n}$"

  只能输入零和非零开头的数字:"^(0|[1-9][0-9]*)$"。

  只能输入有两位小数的正实数:"^[0-9]+(.[0-9]{2})?$"。

  只能输入有1~3位小数的正实数:"^[0-9]+(.[0-9]{1,3})?$"。

  只能输入非零的正整数:"^\+?[1-9][0-9]*$"。

  只能输入非零的负整数:"^\-[1-9][]0-9"*$。

  只能输入长度为3的字符:"^.{3}$"。

  只能输入由26个英文字母组成的字符串:"^[A-Za-z]+$"。

  只能输入由26个大写英文字母组成的字符串:"^[A-Z]+$"。

  只能输入由26个小写英文字母组成的字符串:"^[a-z]+$"。

  只能输入由数字和26个英文字母组成的字符串:"^[A-Za-z0-9]+$"。

  只能输入由数字、26个英文字母或者下划线组成的字符串:"^\w+$"。

  验证用户密码:"^[a-zA-Z]\w{5,17}$"正确格式为:以字母开头,长度在6~18之间,只能包含字符、数字和下划线。

  验证是否含有^%&’,;=?$\"等字符:"[^%&’,;=?$\x22]+"。

  只能输入汉字:"^[\u4e00-\u9fa5]{0,}$"

  验证Email地址:"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$"。

  验证InternetURL:"^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$"。

  验证电话号码:"^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$"正确格式为:"XXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"和"XXXXXXXX"。

  验证身份证号(15位或18位数字):"^\d{15}|\d{18}$"。

  验证一年的12个月:"^(0?[1-9]|1[0-2])$"正确格式为:"01"~"09"和"1"~"12"。

  验证一个月的31天:"^((0?[1-9])|((1|2)[0-9])|30|31)$"正确格式为;"01"~"09"和"1"~"31"。

  利用正则表达式限制网页表单里的文本框输入内容:

  用正则表达式限制只能输入中文:onkeyup="value=value.replace(/[^\u4E00-\u9FA5]/g,’’)" onbeforepaste="cliPBoardData.setData(’text’,clipboardData.getData(’text’).replace(/[^\u4E00-\u9FA5]/g,’’))"

  用正则表达式限制只能输入全角字符: onkeyup="value=value.replace(/[^\uFF00-\uFFFF]/g,’’)" onbeforepaste="clipboardData.setData(’text’,clipboardData.getData(’text’).replace(/[^\uFF00-\uFFFF]/g,’’))"

  用正则表达式限制只能输入数字:onkeyup="value=value.replace(/[^\d]/g,’’) "onbeforepaste="clipboardData.setData(’text’,clipboardData.getData(’text’).replace(/[^\d]/g,’’))"

  用正则表达式限制只能输入数字和英文:onkeyup="value=value.replace(/[\W]/g,’’) "onbeforepaste="clipboardData.setData(’text’,clipboardData.getData(’text’).replace(/[^\d]/g,’’))"

  得用正则表达式从URL地址中提取文件名的JavaScript程序,如下结果为page1

以下是引用片段:
  s="http://www.9499.net/page1.htm"
  s=s.replace(/(.*\/){0,}([^\.]+).*/ig,"$2")
  alert(s)


  匹配双字节字符(包括汉字在内):[^\x00-\xff]

  应用:计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)

以下是引用片段:
  String.prototype.len=function(){return this.replace([^\x00-\xff]/g,"aa").length;}


  匹配空行的正则表达式:\n[\s| ]*\r

  匹配HTML标记的正则表达式:/<(.*)>.*<\/\1>|<(.*) \/>/

  匹配首尾空格的正则表达式:(^\s*)|(\s*$)

以下是引用片段:
  String.prototype.trim = function()
  {
  return this.replace(/(^\s*)|(\s*$)/g, "");
  }


  利用正则表达式分解和转换IP地址:

  下面是利用正则表达式匹配IP地址,并将IP地址转换成对应数值的Javascript程序:

以下是引用片段:
  function IP2V(ip)
  {
  re=/(\d+)\.(\d+)\.(\d+)\.(\d+)/g //匹配IP地址的正则表达式
  if(re.test(ip))
  {
  return RegExp.$1*Math.pow(255,3))+RegExp.$2*Math.pow(255,2))+RegExp.$3*255+RegExp.$4*1
  }
  else
  {
  throw new Error("Not a valid IP address!")
  }
  }

不过上面的程序如果不用正则表达式,而直接用split函数来分解可能更简单,程序如下:

以下是引用片段:
  var ip="10.100.20.168"
  ip=ip.split(".")
  alert("IP值是:"+(ip[0]*255*255*255+ip[1]*255*255+ip[2]*255+ip[3]*1))


  符号解释:

  \

  将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符。例如,’n’ 匹配字符 "n"。’\n’ 匹配一个换行符。序列 ’\\’ 匹配 "\" 而 "\(" 则匹配 "("。

  ^

  匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 ’\n’ 或 ’\r’ 之后的位置。

  $

  匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 ’\n’ 或 ’\r’ 之前的位置。

  *

  匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等价于{0,}。

  +

  匹配前面的子表达式一次或多次。例如,’zo+’ 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。

  ?

  匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。

  {n}

  n 是一个非负整数。匹配确定的 n 次。例如,’o{2}’ 不能匹配 "Bob" 中的 ’o’,但是能匹配 "food" 中的两个 o。

  {n,}

  n 是一个非负整数。至少匹配n 次。例如,’o{2,}’ 不能匹配 "Bob" 中的 ’o’,但能匹配 "foooood" 中的所有 o。’o{1,}’ 等价于 ’o+’。’o{0,}’ 则等价于 ’o*’。

  {n,m}

  m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。’o{0,1}’ 等价于 ’o?’。请注意在逗号和两个数之间不能有空格。

  ?

  当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",’o+?’ 将匹配单个 "o",而 ’o+’ 将匹配所有 ’o’。

  .

  匹配除 "\n" 之外的任何单个字符。要匹配包括 ’\n’ 在内的任何字符,请使用象 ’[.\n]’ 的模式。

  (pattern)

  匹配 pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 $0…$9 属性。要匹配圆括号字符,请使用 ’\(’ 或 ’\)’。

  (?:pattern)

  匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, ’industr(?:y|ies) 就是一个比 ’industry|industries’ 更简略的表达式。

  (?=pattern)

  正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,’Windows (?=95|98|NT|2000)’ 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。

  (?!pattern)

  负向预查,在任何不匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如’Windows (?!95|98|NT|2000)’ 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始

  x|y

  匹配 x 或 y。例如,’z|food’ 能匹配 "z" 或 "food"。’(z|f)ood’ 则匹配 "zood" 或 "food"。

  [xyz]

  字符集合。匹配所包含的任意一个字符。例如, ’[abc]’ 可以匹配 "plain" 中的 ’a’。

  [^xyz]

  负值字符集合。匹配未包含的任意字符。例如, ’[^abc]’ 可以匹配 "plain" 中的’p’。

  [a-z]

  字符范围。匹配指定范围内的任意字符。例如,’[a-z]’ 可以匹配 ’a’ 到 ’z’ 范围内的任意小写字母字符。

  [^a-z]

  负值字符范围。匹配任何不在指定范围内的任意字符。例如,’[^a-z]’ 可以匹配任何不在 ’a’ 到 ’z’ 范围内的任意字符。

  \b

  匹配一个单词边界,也就是指单词和空格间的位置。例如, ’er\b’ 可以匹配"never" 中的 ’er’,但不能匹配 "verb" 中的 ’er’。

  \B

  匹配非单词边界。’er\B’ 能匹配 "verb" 中的 ’er’,但不能匹配 "never" 中的 ’er’。

\cx

  匹配由 x 指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 ’c’ 字符。

  \d

  匹配一个数字字符。等价于 [0-9]。

  \D

  匹配一个非数字字符。等价于 [^0-9]。

  \f

  匹配一个换页符。等价于 \x0c 和 \cL。

  \n

  匹配一个换行符。等价于 \x0a 和 \cJ。

  \r

  匹配一个回车符。等价于 \x0d 和 \cM。

  \s

  匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。

  \S

  匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。

  \t

  匹配一个制表符。等价于 \x09 和 \cI。

  \v

  匹配一个垂直制表符。等价于 \x0b 和 \cK。

  \w

  匹配包括下划线的任何单词字符。等价于’[A-Za-z0-9_]’。

  \W

  匹配任何非单词字符。等价于 ’[^A-Za-z0-9_]’。

  \xn

  匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,’\x41’ 匹配 "A"。’\x041’ 则等价于 ’\x04’ & "1"。正则表达式中可以使用 ASCII 编码。.

  \num

  匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,’(.)\1’ 匹配两个连续的相同字符。

  \n

  标识一个八进制转义值或一个向后引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为向后引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。

  \nm

  标识一个八进制转义值或一个向后引用。如果 \nm 之前至少有 nm 个获得子表达式,则 nm 为向后引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的向后引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。

  \nml

  如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。

  \un

  匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (?)。

C#也能动态生成Word文档并填充数据

要使用C#操作word,首先要添加引用:
1、添加引用->COM->Microsoft Word 11.0 Object Library

2、在.cs文件中添加

using Word;
下面的例子中包括C#对Word文档的创建、插入表格、设置样式等操作:

(例子中代码有些涉及数据信息部分被省略,重要是介绍一些C#操作word文档的方法)

public string CreateWordFile(string CheckedInfo)
...{
string message = "";
try
...{
Object Nothing = System.Reflection.Missing.Value;
Directory.CreateDirectory("C:/CNSI"); //创建文件所在目录
string name = "CNSI_" + DateTime.Now.ToShortString()+".doc";
object filename = "C://CNSI//" + name; //文件保存路径
//创建Word文档
Word.Application WordApp = new Word.ApplicationClass();
Word.Document WordDoc = WordApp.Documents.Add(ref Nothing, ref Nothing, ref Nothing, ref Nothing);

//添加页眉
WordApp.ActiveWindow.View.Type = WdViewType.wdOutlineView;
WordApp.ActiveWindow.View.SeekView = WdSeekView.wdSeekPrimaryHeader;
WordApp.ActiveWindow.ActivePane.Selection.InsertAfter("[页眉内容]");
WordApp.Selection.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphRight;//设置右对齐
WordApp.ActiveWindow.View.SeekView = WdSeekView.wdSeekMainDocument;//跳出页眉设置

WordApp.Selection.ParagraphFormat.LineSpacing = 15f;//设置文档的行间距

//移动焦点并换行
object count = 14;
object WdLine = Word.WdUnits.wdLine;//换一行;
WordApp.Selection.MoveDown(ref WdLine, ref count, ref Nothing);//移动焦点
WordApp.Selection.TypeParagraph();//插入段落

//文档中创建表格
Word.Table newTable = WordDoc.Tables.Add(WordApp.Selection.Range, 12, 3, ref Nothing, ref Nothing);
//设置表格样式
newTable.Borders.OutsideLineStyle = Word.WdLineStyle.wdLineStyleThickThinLargeGap;
newTable.Borders.InsideLineStyle = Word.WdLineStyle.wdLineStyleSingle;
newTable.Columns[1].Width = 100f;
newTable.Columns[2].Width = 220f;
newTable.Columns[3].Width = 105f;

//填充表格内容
newTable.Cell(1, 1).Range.Text = "产品详细信息表";
newTable.Cell(1, 1).Range.Bold = 2;//设置单元格中字体为粗体
//合并单元格
newTable.Cell(1, 1).Merge(newTable.Cell(1, 3));
WordApp.Selection.Cells.VerticalAlignment = Word.WdCellVerticalAlignment.wdCellAlignVerticalCenter;//垂直居中
WordApp.Selection.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;//水平居中

//填充表格内容
newTable.Cell(2, 1).Range.Text = "产品基本信息";
newTable.Cell(2, 1).Range.Font.Color = Word.WdColor.wdColorDarkBlue;//设置单元格内字体颜色
//合并单元格
newTable.Cell(2, 1).Merge(newTable.Cell(2, 3));
WordApp.Selection.Cells.VerticalAlignment = Word.WdCellVerticalAlignment.wdCellAlignVerticalCenter;

//填充表格内容
newTable.Cell(3, 1).Range.Text = "品牌名称:";
newTable.Cell(3, 2).Range.Text = BrandName;
//纵向合并单元格
newTable.Cell(3, 3).Select();//选中一行
object moveUnit = Word.WdUnits.wdLine;
object moveCount = 5;
object moveExtend = Word.WdMovementType.wdExtend;
WordApp.Selection.MoveDown(ref moveUnit, ref moveCount, ref moveExtend);
WordApp.Selection.Cells.Merge();
//插入图片
string FileName = Picture;//图片所在路径
object LinkToFile = false;
object SaveWithDocument = true;
object Anchor = WordDoc.Application.Selection.Range;
WordDoc.Application.ActiveDocument.InlineShapes.AddPicture(FileName, ref LinkToFile, ref SaveWithDocument, ref Anchor);
WordDoc.Application.ActiveDocument.InlineShapes[1].Width = 100f;//图片宽度
WordDoc.Application.ActiveDocument.InlineShapes[1].Height = 100f;//图片高度
//将图片设置为四周环绕型
Word.Shape s = WordDoc.Application.ActiveDocument.InlineShapes[1].ConvertToShape();
s.WrapFormat.Type = Word.WdWrapType.wdWrapSquare;

newTable.Cell(12, 1).Range.Text = "产品特殊属性";
newTable.Cell(12, 1).Merge(newTable.Cell(12, 3));
//在表格中增加行
WordDoc.Content.Tables[1].Rows.Add(ref Nothing);

WordDoc.Paragraphs.Last.Range.Text = "文档创建时间:" + DateTime.Now.ToString();//“落款”
WordDoc.Paragraphs.Last.Alignment = Word.WdParagraphAlignment.wdAlignParagraphRight;

//文件保存
WordDoc.SaveAs(ref filename, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing);
WordDoc.Close(ref Nothing, ref Nothing, ref Nothing);
WordApp.Quit(ref Nothing, ref Nothing, ref Nothing);
message=name+"文档生成成功,以保存到C:CNSI下";
}
catch
...{
message = "文件导出异常!";
}
return message;
}

  查阅关于C#的全部文档

C#和ASP.NET开发的一些小技巧及注意事项

  1、构造函数不能带返回值类型,因为构造函数返回就是对象本身。

  2、将字符串转换成日期类型,用DateTime.Parese()或DateTime.ParseExact()函数。

  3、if(!Page.IsPostback){}

  使用该函数,使网页仅在第一次加载时运行函数体的内容,在Page_Load()事件中,通常可用于初始化。如果不使用该函数,则可能会在一些控件回传时再次运行if()函数体内的内容,导致相关控件修改后的值没有正确应用。

  4、GridView的字段(BoundField)有一个属性HtmlEncode。这个属性用于将HTML进行包装,如果为true(默认值),则原样显示字段内的内容。如果为false,则将字段内相应的HTML标签进行渲染。因此,要使字段内的图片链接显示出来,应设置HtmlEncode=“true”。

  5、网页中获取日期后进行格式化的方法:Eval("wtDate", "{0:yyyy-MM-dd}")但在DateTime.Now.Date.ToString("yyyy-MM-dd") 中的字符串格式化却有所不同。

  6、NVarChar数据类型,在SQL SERVER 2005中具有NVarChar(max)类型来代表最大为2^32 的数字,但是在.net2.0中并不支持这个类型,NVarChar最大能表示的数仍为4000字节。

  7、将字符串类型转换为Guid类型,可将字符串作为Guid构造函数的参数进行传递。

如: Guid gd = New Guid(string);
Guid类型的空值为Guid.Empty ,而非null。

  8、最好对各字段都存储值,即便不使用,也就进行初始设置,以避免为空值时,出现数据类型不匹配现象,如DateTime,uniqueIdentifier字段,取出空值进行处理时会带来麻烦。

  9、对记录数进行统计,使用类似下面的语句:

int cout =(int)cmd.ExecuteScalar();

  10、存储过程中,通配符与参数结合使用,要采用字符串加法,而不能直接放在参数两侧,如下:

WHERE RTRIM(f.ftTitle) LIKE '%'+RTRIM(@searchkey)+'%'

  11、要获取list对象中某个项的值,可采用如下方法:

  如List CurrentFault = new List();//创建一个对象

   假设ftInfo类中定义了ftIsResovled属性,那么,要获取CurrentFault的第0项的ftIsResolved值,可通过语名: CurrentFault[0].ftIsResolved 来获得。

  12、Input控件中包含有标签的内容(如)时,可能会有如下因为安全问题引起的错误:说明: 请求验证过程检测到有潜在危险的客户端输入值,对请求的处理已经中止。该值可能指示危及应用程序安全的尝试,如跨站点的脚本攻击。通过在 Page 指令或 配置节中设置 validateRequest=false 可以禁用请求验证。但是,在这种情况下,强烈建议应用程序显式检查所有输入。

  13、显示带有HTML标记的字段内容,如果需要渲染HTML标签,可以设置htmlencode属性为true。设置为false时,字段内的HTML标签将按普通字符显示。也可以使用HtmlEncode()方法来渲染字段内容的HTML标签。

  14、LoginStatus控件可以方便地显示登录状态,并且提供登录和注销的快捷链接。但有时并不方便,特别是注销的同时要退出框架网页时,使用该控件就显得力不从心。可以直接使用LinkButton控件,在点击事件中,添加如下两句,就可以实现注销的同时跳转到框架网页的父窗口:

FormsAuthentication.SignOut();
Response.Write("");

  15、C#中关闭窗口:

Response.Write("");

如何才能学好C#

  1.微软支持
  在你学习VS.NET的过程中,有疑问首先要向MicroSoft求助。如果你不懂得利用MicroSoft提供的庞大的学习资源,我要告诉你,你很不幸,你舍近求远了。
  (1)首先,你要安装MSDN,他比所有VS.NET书籍详细。我为了装MSDN,可是牺牺了我的98和XP双启动,改成WindowsXP单系统。装了MSDN后,你要学习正则表达式,VS.NET 2003中点击“帮助”,再点击“搜索”,然后输入“正则”,一回车,哇,找到470个主题,这下你慢慢研究吧。实在研究不透,也不用急,还有Google和CSDN呢。   
  (2)在线Microsoft .NET 框架 SDK 快速入门教程(http://chs.gotdotnet.com/QuickStart),可配合MSDN使用。分三块内容, ASP.NET | Windows 窗体 | 如何...?常见任务 。 “常见任务快速入门”旨在帮助您快速找到常见编程问题的答案。
  (3)微软中国社区(http://www.mscommunity.com/Profile/)。在社区注册,有问题就到社区去提问吧。
  (4)在线中文MSDN(http://www.microsoft.com/china/MSDN/default.asp);在线英文MSDN(http://msdn.microsoft.com/),考考你的E文,不过有金山词霸在,我都不怕,你还用怕什么呢!
  (5).NET主页(http://www.microsoft.com/china/net)
  (6)Visual Studio .NET主页(http://www.microsoft.com/china/msdn/vstudio/prodinfo/overview.asp)。
   为什么选择VS.NET,为什么看好VS.NET,看看MicroSoft的Help文档有多详尽就知道了。如果你不去利用MicroSoft提供的庞大的Help资源,是不是有点对不起盖茨呢!  
  2.CSDN http://www.csdn.net/
  CSDN号称最大的开发者网络,确实不假。我最常去的是CSDN的
  文档(http://www.csdn.net/develop/)
  论坛(http://expert.csdn.net/expert/forum.asp)
  只要你善于利用搜索功能,你在开发中遇到的多数问题可在文档和论坛中找到答案。如果你在开发过程中遇到疑难,而你又认为 BillGates帮不上你的忙,那么,你就上CSDN吧,一定会让你满意的。
   教你两个绝招,第一招,是“搜索大法”。遇到问题,首先是在CSDN的文档和论坛进行搜索,看有无类似答案。如不行,再下一招。
   第二招,“提问大法”,只要有礼貌有诚意地在论坛提问,一定有许多人乐于回答你的问题。
  3.其他相关网站
   有不少网站开辟VS.NET专栏,常去看看,必有收获。
  pconline跟我学NET专栏(http://www.pconline.com.cn/pcedu/empolder/net/)
  yesky的Visual Studio.NET专栏(http://www.yesky.com/SoftChannel/72342380467978240/index.shtml)
  ccidnet的NET专区(http://tech.ccidnet.com/pub/column/c340.html)
  4.资料下载
  如果不是包月上网,那么下载大量资源,再断线慢慢研究就很有必要了。
  91asp提供电子书下载(http://www.91asp.cn/)
  网友提供的大量VS.NET资源下载(ftp://qydn.vicp.net) 
北京希望电子出版社图书素材资料下载(http://www.b-xr.com/bbs.htm)
 
  清华大学出版社VS.NET源码下载(http://www.wenyuan.com.cn/xiazai.htm)
  5.国外资源
   如果你的E文不错,不妨上E文网站去取经。
  http://www.codestudy.com
  http://www.codeproject.com
  http://www.only4gurus.com/v2
  http://www.gotdotnet.com
  http://www.aspnetpro.com
  6.其他特色网站、专栏
  CSDN上Latitude的VS.NET专栏(http://www.csdn.net/develop/author/netauthor/Latitude/)
  【孟宪会之精彩世界】(http://xml.sz.luohuedu.net/xml/) 
  DotNet中华网(http://www.aspxcn.com/)
   ASP酷(http://www.aspcool.com/)
  http://www.chinaaspx.com
   当然,还有一个地球人都知道的,全球最大的知识仓库,我不说,你也早就应该知道的,那不是http://www.google.com又是什么!

  个人体会:掌握并利用大量网络资源来辅助VS.NET的学习,你将事半功倍。

C#语言基础常见问题汇总

概述

1、什么是C#?

C#是Microsoft公司设计的一种编程语言。它松散地基于C/C++,并且有很多方面和Java类似。

Microsoft是这样描述C#的:“C#是从C和C++派生来的一种简单、现代、面向对象和类型安全的编程语言。C#(读做‘Csharp’)主要是从C/C++编程语言家族移植过来的,C和C++的程序员会马上熟悉它。C#试图结合Visual Basic的快速开发能力和C++的强大灵活的能力。”

2、如何开发C#应用程序?

.NET SDK包括了C#命令行编译器(csc.exe),下一个版本的Visual Studio (Visual Studio 7 or Visual Studio.NET)会包含对C#开发的完整支持。

3、C#可以取代Java?

C#非常像Java语言——这两种语言的核心和C++相比都有相似的优缺点。例如,两个语言都有垃圾回收,但是两个语言都没有模板(template)。Microsoft已经中止了Visual J++产品,因此很难不认为Microsoft在使用C#来替代Java。

4、C#可以取代C++?

显然是不,但是我们又很难说C++是新的.NET平台上编写代码的最佳选择。为了使.NET的运行层能完全发挥作用,它要求编程语言遵循某些特定的规则——其中之一就是所有的语言类型必须遵守通用类型系统(Common Type System,CTS)。不幸的是,许多C++特性不能被CTS支持。例如,模板和类的多重继承。

Microsoft对这个问题的答案是给C++提供可管理的扩展(Managed Extensions,ME), 这可以使C++遵守CTS。通过添加新的关键字来标记C++类有CTS的属性(例如.-gc表示垃圾回收)。但是在创建新的工程时很难讲为什么ME C++会比C#更合适。就特征(feature)而言它们很相似,但与C++不同的是C#从一开始就以.NET为环境设计的。ME C++存在的理由好像是将C++代码移植(port)为.NET环境下的代码。

因此,这个问题的答案,很可能是C++作为一个.NET环境之外的语言将依然保留它的重要性;而通过ME将现存的C++代码移植为适合.NET环境;但是很可能C#将是C++开发者开发新的.NET应用程序的最好选择。

8、C#是面向对象的吗?

是的,C#像Java和C++一样,是一个面向对象的语言。

9、C#有自己的类库吗?

不,就像所有的.NET语言(VB.Net,JScript .Net...)一样,C#访问.NET类库,C#没有自己的类库。

基本类型

1、C#提供什么标准类型?

C# 支持的基本类型和C++很相似,包括int, long, float, double, char, string, arrays, structs 和 classes。然而,不要假设太多,名字可能很形似,但是一些细节不相同。例如C#中的long是64位的,而C++的long取决于平台,32位的平台上是32位的,64位的平台上是64位的。class和struct在C++中几乎完全一样,但在C#中并不是这样的。

2、是否所有的C#类型都派生于一个公共的基类?

是,也不是,所有的对象都可以看作从Object (System.Object)派生而来。但是为了把像int,float这样的值类型实例看作是从Object对象派生的,这个实例必须通过一个装箱的操作(boxing)转化为引用类型。理论上,开发者可以忽略这些底层的转化,但是认识到这点对于系统性能影响很重要。

3、是否可以这样认为,可以将一个值类型的实例作为参数传给以对象为参数的方法?

是的,例如:

class CApplication {
public static void Main() {
int x = 25;
string s = “fred”;
DisplayMe( x );
DisplayMe( s ); }
static void DisplayMe( object o ) {
System.Console.WriteLine( “You are {0}”, o ); }}

将显示:

You are 25
You are fred

4、值类型和引用类型的最基本的区别是什么?

C#将类型分为两类,一类是值类型,另一类是引用类型。大部分固有的基本类型(如int, char)是值类型,structs 也是值类型。引用类型包括类、接口、数组和字符串。基本的概念非常简单,那就是一个值类型的实例代表了实际的数据(存在栈中),而一个引用类型的实例代表指向数据的指针或者引用(存在堆中)。

C++开发者最容易混淆的地方是:C#已经自己预定义了一些类型作为值类型,一些作为引用类型,而一个C++的开发者希望能够自己控制。

例如,在C++中,我们可以这样做:

int x1 = 3; // x1 是堆栈上的值
int *x2 = new int(3) // x2 是堆的一个值的引用

但是在C#中没有这样的控制:

int x1 = 3; // x1是堆栈上的值
int x2 = new int();
x2 = 3; // x2还是堆栈上的值!

5、既然 int是值类型,而 class是引用类型,那么int是怎样从Object派生的呢?

是这样的,当int用作int时候,这是一个值类型(在栈上),然而,当它用作是Object时,这是一个引用堆上的整数值的引用类型。换而言之,当你将int看作对象时,运行层将它自动转化为对象引用,这个转化过程称作装箱(boxing)。这个转换包括将栈里的值拷贝到了堆里,并且新建了一个对象的实例来引用该值。拆箱操作(unboxing)是个反过程——将对象转化为基于栈的值类型。

int x = 3;
// 堆栈上新的int类型,值为3
object objx = x;
// 堆上新的int, 设定值为3,x=3仍然在堆栈上
int y = (int)objx;
//新的int类型的值3在堆栈上,x=3在堆栈上,objx=3在堆上

6、C#使用引用替代指针,那么C#的引用和C++的引用一样吗?

不完全,基本的思想是一样的,但是一个重要的区别是C#的引用可以是null。因此你不能确认C#的引用一定会是一个有效的对象。如果试图使用一个值为null的引用,一个NullReferenceException 异常将被抛出。

例如,看一看以下的方法:

void displayStringLength( string s ) {
Console.WriteLine( “String is length {0}”, s.Length ); }

如果这样调用它,这种方法将产生一个NullReferenceException 异常:

string s = null;
displayStringLength( s );

当然有些情况你认为产生这样一个异常是完全可以接受的结果,但是在这个例子里最好按下面的代码改写一下:

void displayStringLength( string s ) {
if( s == null )
Console.WriteLine(“String is null”);
else
Console.WriteLine(“String is length {0}”, s.Length );
}

class和struct

1、struct在C++中是多余的,为什么C#还要使用它们呢?

在C++中,一个结构和一个类几乎就是一个同样的东西。唯一的区别是缺省的成员的访问级别不一样(struct的缺省级别是public,class的缺省级别是private)。然而,在C#中struct和class完全不一样。在C#中,struct 是值类型,而class是引用类型。另外struct不能从其他struct或者class继承,尽管struct可以实现接口。struct没有析构器。

2、C#支持多重继承吗?

C#支持接口的多重继承,但是不支持类的多重继承。

3、C#接口和C++抽象类一样吗?

不,不完全。C++的抽象类不能被实例化。但是它可以(而且经常是)包含执行代码和数据成员。一个C#接口不能包含任何执行代码或数据成员,它只是一组方法名称和签名(signature)。一个C#的接口更像是一个COM接口而不是抽象类。

另一个主要的不同点是:C#类只能从一个类(不管是否抽象)继承,但可以实现多重接口。

4、C#构造器和C++ 构造器是否相同?

非常相似,但是它们绝对不同。第一,C#析构器不保证在某个特定的时间被调用。实际上它根本不保证被调用。真实的情况是,C#析构器只是一个伪装了的Finalize方法。具体点讲,它是一个插入调用基类Finalize方法的Finalize方法。因此,这段代码:

class CTest {
~CTest() {
System.Console.WriteLine(“Bye bye” );
}
}

实际上就是:

class CTest {
protected override void Finalize() {
System.Console.WriteLine(“Bye bye” );
base.Finalize();
}
}

如果你不相信,可以将一个 Finalize方法和一个析构器加入C#类中,然后就可以知道是如何编译的了。

5、什么是静态构造器?

它是整个类的一个构造器,而不是类的一个实例的构造器,它在类装载的时候被调用。

6、C#中所有的方法都是虚方法吗?

不,像C++一样,缺省的时候,方法不是虚拟的,但都可以改为虚拟的。

7、怎样在C#中声明一个纯虚函数?

在方法前使用abstract修饰符,类也可以标记为abstract(这是自然的)。注意,abstract方法不能有执行代码(不同于C++中纯虚方法)。

和C++处理的不同

1. 我“new”了一个对象,但是我怎样删除它?

你不能,不允许你显式地调用析构器,也没有delete操作符。但是不必担心,垃圾回收(garbage collection)会释放你的对象,最终会的(也许会的)。

2. 我试图在栈上建立一个对象,但是C#编译器不通过,这是怎么回事?

和C++不同,你不能在栈上建立一个对象的实例。类的实例总是被建立在堆上并且接受垃圾回收器(garbage collection)的管理。

3. 我定义了一个析构器,但是它从来不能被调用,为什么?

一个C#析构器实际上是Finalize方法的实现,但是运行环境不保证调用Finalize方法。你可以考虑通过调用GC.RequestFinalizeOnShutdown()方法试一下。

4. 大多数的C#基本类型和C++的基本类型有相同的名字,它们一样吗?

不,C#中char和C++中的wchar是相同的。C#中所有的字符包括字符串都是Unicode的,C#中整型值是固定大小的,而在C++中其大小取决于处理器。例如,一个C#的int是32位的,而C++ 中int在32-bit处理器上是32位的,在64-bit处理器上是64位的,一个C#的long是64位的。