正则&泛型
1、正则表达式:有效验证用户输入的格式是否满足要求。
一下是常用的正则表达式,在这里列举一下,以后可能会用到哦!
匹配
首尾空白字符的正则表达式:^\s*|\s*$
评注:可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式
匹配
Email地址的正则表达式:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
评注:表单验证时很实用
匹配
网址URL的正则表达式:[a-zA-z]+://[^\s]*
评注:网上流传的版本功能很有限,上面这个基本可以满足需求
匹配
帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
评注:表单验证时很实用
匹配
国内电话号码:\d{3}-\d{8}|\d{4}-\d{7}
评注:匹配形式如 0511-4405222 或 021-87888822
匹配
腾讯QQ号:[1-9][0-9]{4,}
评注:腾讯QQ号从10000开始
匹配
中国邮政编码:[1-9]\d{5}(?!\d)
评注:中国邮政编码为6位数字
匹配
身份证:\d{15}|\d{18}
评注:中国的身份证为15位或18位
匹配
ip地址:\d+\.\d+\.\d+\.\d+
评注:提取ip地址时有用
匹配
特定数字:
^[1-9]\d*$ //匹配正整数
^-[1-9]\d*$ //匹配负整数
^-?[1-9]\d*$ //匹配整数
^[1-9]\d*|0$ //匹配非负整数(正整数 + 0)
^-[1-9]\d*|0$ //匹配非正整数(负整数 + 0)
^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ //匹配正浮点数
^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ //匹配负浮点数
^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$ //匹配浮点数
^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$ //匹配非负浮点数(正浮点数 + 0)
^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$ //匹配非正浮点数(负浮点数 + 0)
评注:处理大量数据时有用,具体应用时注意修正
匹配特定
字符串:
^[A-Za-z]+$ //匹配由26个英文字母组成的字符串
^[A-Z]+$ //匹配由26个英文字母的大写组成的字符串
^[a-z]+$ //匹配由26个英文字母的小写组成的字符串
^[A-Za-z0-9]+$ //匹配由数字和26个英文字母组成的字符串
^\w+$ //匹配由数字、26个英文字母或者下划线组成的字符串
2、泛型:通过泛型可以定义类型安全的数据结构,而无须使用实际的数据类型,简单理解就是将类型作为参数,这能够显著提高性能并得到更高质量的代码,
说明:
1)使用泛型类型可以最大限度地重用代码、保护类型的安全以及提高性能。
2)泛型最常见的用途是创建集合类。
3).NET Framework 类库在 System.Collections.Generic 命名空间中包含几个新的泛型集合类。
应尽可能地使用这些类来代替普通的类,如 System.Collections 命名空间中的 ArrayList。
4)您可以创建自己的
泛型接口、泛型类、泛型方法、泛型事件和泛型委托。
5)可以对泛型类进行约束以访问特定数据类型的方法。
6)关于泛型数据类型中使用的类型的信息可在运行时通过使用反射获取。
注:定义泛型时如果只有一个参数,建议使用T(表示type),这个类型可以为任意object类型;
例:
class Program
{
static void Main(string[] args)
{
Fan<int>(20);
Fan<double>(3.2);
Fan<Program>(new Program());//此时传一个Program类型的参数也可以,
}
/// <summary>
/// 定义一个泛型方法,有一个类型的参数为T,传入一个类型为T的参数t,
/// 方法内部打印出所传入的参数的类型和值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
static void Fan<T>(T t)
{
Console.WriteLine("类型{0},值{1}",t.GetType(),t);
}
}
上例中可以添加类型约束来限制只能访问特定类型
2、泛型约束:约束是使用 where 上下文关键字指定的
约束的种类有以下6种:
1)结构约束:类型参数必须是值类型。可以指定除 以外的任何值类型。
static void Main(string[] args)
{
PrintType<int>(5);//正确的写法
PrintType<string>(“泛型真伟大”);//错误的写法
}
static void PrintType<T>(T i) where T: struct
{
Console.WriteLine("类型:{0,-20} 值:{1}",i.GetType (),i);
}
2)类约束:类型参数必须是
引用类型;这一点也适用于任何类、接口、委托或数组类型。
3)new()约束:类型参数必须
具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。
4)<基类名>:类型参数必须是
指定的基类或派生自指定的基类。
5)<接口名称>:类型参数必须是
指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。
class Program
{
static void Main(string[] args)
{
PrintType<IDemo>(new Demo()); //正确
PrintType<Demo>(new Demo()); //正确
}
static void PrintType<T>(T i) where T : IDemo
{
Console.WriteLine("类型:{0,-20} 值:{1}", i.GetType(), i);
}
}
interface IDemo
{ }
class Demo : IDemo
{ }
6)U:为 T 提供的类型参数必须是
为 U 提供的参数或派生自为 U 提供的参数。这称为裸类型约束。
class Program
{
static void Main(string[] args)
{
PrintType<IDemo,Demo>(new Demo()); //错误
PrintType<Demo,IDemo>(new Demo()); //正确
PrintType<Demo, Demo>(new Demo()); //正确
}
static void PrintType<T,U>(T i) where T : U
{
Console.WriteLine("类型:{0,-20} 值:{1}", i.GetType(), i);
}
}
interface IDemo
{ }
class Demo : IDemo
{ }
3、default:使用 default 关键字,此关键字对于引用类型会返回 null,对于数值类型会返回零,对于结构,此关键字将返回初始化为零或 null 的每个结构成员,具体取决于这些结构是值类型还是引用类型
小练习:自己做一个泛型集合(像微软的ArrayList)MyList,实现最基本的功能
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
MyList<int> mylist = new MyList<int>();
mylist.Add(20);
mylist.Add(10);
mylist.Remove(10);
mylist.Add(20);
Console.WriteLine(mylist.Count );
Console.WriteLine(mylist.Capacity );
Console.WriteLine(mylist[0]);
foreach (int a in mylist)
{
Console.WriteLine(a);
}
}
}
class MyList<T>:IEnumerable
{
T[] list=new T [0];
public int count;
public int Count
{
get
{
return count;
}//count为只读
}
/// <summary>
/// 属性容量
/// </summary>
public int Capacity
{
get
{
return list.Length ;
}
set
{
if (value < count)
{
throw new Exception("集合容量小于元素个数!");
}//如果设置容量的值小于集合长度,就抛出异常
else
{
list=new T[value ];
}//如果不小于就将集合的容量设置为指定的值
}
}
/// <summary>
/// 删除集合中的元素
/// </summary>
/// <param name="t"></param>
public void Remove(T t)
{
for (int i = 0; i < count; i++)
{
int index = -1;
if (list[i].Equals(t))//找出要删除的元素,得到该元素所在集合的下标
{
for (index = i; index < count - index; index++)
{
list[index]=list[index+1];
}//将要删除的集合后面的元素往前移动
list[count]=default (T);//将集合中最后一个元素的值赋为该类型的默认值
count--;//集合元素个数减1
}
}
}
/// <summary>
/// 集合元素的增加
/// </summary>
/// <param name="t"></param>
public void Add(T t)
{
if (list.Length ==count)//注:此处不可能会出现数组长度小于count的,什么原因自己好好想想,
//大于就更不用说了,直接利用list[count] = t;count++;做处理就可以了
{
if (count == 0)
{
list=new T[4];
}//如果数组中没有元素,并且容量等于长度也为0,则此时给数组赋一个容量是4
else
{
T[] newlist = new T[count * 2];
for (int i = 0; i < count; i++)
{
newlist[i] = list[i];
}
list = newlist;
} //else表示元素个数等于数组容量且都不为0这时数组就要成倍扩展容量 ,此时可以定义一个新
//数组,数组容量为原来容量的2倍,然后遍历原来的数组将原来数组的元素复制给新数组对应的
//下标,最后把新数组赋值给原来的数组
}
list[count] = t;
count++;//上面的操作完成了,在数组末尾增加元素,并将元素个数加1
}
/// <summary>
/// 索引器,实现根据集合的下标取值
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
public T this[int t]
{
get
{
return list[t];
}
set
{
list[t] = value;
}
}
/// <summary>
/// 实现集合的遍历输出
/// </summary>
/// <returns></returns>
public IEnumerator GetEnumerator()
{
for (int i = 0; i < count; i++)
{
yield return list[i];
}
}
}
}
回忆一下: 引用类型在打印时调用的是ToString()方法,可以利用override重构ToString()方法使其按照固定格式输出。