WinForm
Console.WriteLine() //屏幕上输出一行字
Console.RreadLine()//请求用户输入一段文字
Console.ReadKey()//请求用户按一个键
Console.WriteLine("{0}love{1}",name1,name2);
汉字也表示一个字符 int64==long int32==int
string name=@"anem
abcsdfas";//可以用@声明多行的字符串
enum QQStatus{online,hedden} 枚举类型
int[] nms={3,5,6}
int[] nums=new int[3];
方法的可变参数:可变参数必须是参数的最后一个
//个数不确定的可变参数以数组的形式传递
int max(params int[] values)
{}
参数默认值 (C#4.0)
SayHello(string name,int age=20) age 调用时可传,也可不传,不传的时候默认为20
不需要为ref 赋值
static void Swap(ref int i1, ref int i2)
{}
Swap(ref i1,ref i2)ref传的是值的引用
不需要为OUT赋值
static void Swap( int i1, out int i2)
{
方法结束时必须为out赋值
}
调用Swap( i1,out i2)
string.IsNullOrEmpty(s)
string s1 = string.Join("|", values);//第一个参数是string类型分隔符string[] Split(params char[] separator):将字符串按照指定的分割符分割为字符串数组;
System.IO.File.ReadAllLines(@"c:\root.ini", Encoding.Default);从文本文件读取数据,返回值为string数组,每个元素是一行。
字符串函数详解
字符串替换:string Replace(string oldValue, string newValue)将字符串中的出现oldValue的地方替换为newValue。例子:名字替换。
取子字符串:string Substring(int startIndex),取从位置startIndex开始一直到最后的子字符串;
string Substring(int startIndex, int length),取从位置startIndex开始长度为length的子字符串,如果子字符串的长度不足length则报错。案例:截取字符串前5个,string s2 = s1.Substring(0, Math.Min(s1.Length, 5));//取字符串的长度和5中的最小值来截取。谁小取谁。
bool Contains(string value)判断字符串中是否含有子串value
bool StartsWith(string value)判断字符串是否以子串value开始;
bool EndsWith (string value)判断字符串是否以子串value结束;
int IndexOf(string value):取子串value第一次出现的位置。
变量名规范:第一个字符小写,其后的每个单词的第一个字母大写
面向对象的三个特性:封装、继承、多态。
类、对象。“人”是类,“张三”是“人”这个类的对象。类是抽象的,对象是具体的。
字段、方法、属性 都可以叫做类的成员Member
字段Field(和某个对象相关的变量),字段就是类的状态(不同的对象可能不一样的状态就是字段)。人这个类有姓名、年龄、身高等字段。类不占内存,对象才占内存。字段描述对象特点的数据
方法Method(函数),方法就是类能够执行的动作
public(任何地方都可以访问);private(默认级别。只能由本类中的成员访问)
永远不要把字段public
字段一般都是private
字段开头小写
惯用法:属性开头字母大写,字段开头字母小写允许外部访问的值一定要声明为属性。
字段和属性的区别是什么?属性看似字段、不是字段,可以进行非法值控制,可以设置只读。
int、decimal、bool、byte、enum等基础类型(值类型)是传递拷贝;对象(引用类型)则是传递引用。因为基础类型不怎么占内存,而对象则比较占内存。
//as 运算符
Chinese ch = p as Chinese ;
if(ch!=null)
{
Console.WriteLine("中国人");
}
()转换和as 转换的区别:如果转换失败()会报异常,而as则会返回null。
is用来判断变量指向的对象是否是指定的类型或者指定类型子类类型。as可以起到判断类型和转换的双重作用。
Exception 类主要属性:Message、StackTraceconst
- const常量。常量名要大写。一定不会变化的值才能声明为常量。
- 全局变量。static类变量。readonly
常量。常量名要大写。一定不会变化的值才能声明为常量
sealed不能被继承
System.Collections.ArrayList,快速引入的方法,右键→解析(Ctrl+.)
命名空间不一定和文件夹结构、名称一致。易错:把cs移动到其他文件夹下不会自动更新namespace。
C#中提供了按照索引器进行访问的方法
定义索引器的方式:string this[int index]{get { return ""; }set { }},string为索引器的类型,[]中是参数列表。进行索引器写操作就是调用set代码块,在set内部使用value得到用户设置的值;进行读操作就执行get代码块。
索引器参数可以不止一个,类型也不限于int,几乎可以是任意类型。
文本框的几种模式:Multiline(多行)、PasswordChar(密码)
退出程序this.Close()或者Application.Exit()
虚方法:使用virtual关键字修饰,使用virtual关键字修饰的方法在本类中必须有实现,哪怕是空的{}。虚方法存在的意义就是为了让子类重写。子类可以重写,也可以不重写。
方法重写:只有用virtual、abstract、override修饰的方法在继承后子类可以重写。//实现方法重写的方式3个关键字
什么是方法重写?答:方法重写是指子类继承父类后在子类中有一个与父类中某个方法签名一致,但方法内容可以重新定义的方法,并用override关键字修饰。
抽象类:abstract关键字修饰;不能实例化;可以有抽象成员也可以有非抽象成员(1.有抽象成员的类必须标记为abstract,并且不能有任何实现;2.类中的抽象成员在子类中必须实现(override),除非子类也是抽象类);
virtual方法和abstract方法的区别:
virtual方法子类可以override,也可以不override。
Abstract标记的成员在子类中必须override,除非子类也是抽象类。
ToString()方法、Equals()来自于Object,任何类都有,通过override有了不同的实现
Virtual注意:
1.使用virtual关键字表示方法,写在返回值的签名public virutal或virtual public
2.使用virutal关键字修饰的方法必须有实现{}
3.子类可以重写,也可以不重写。
子类重写时使用override关键字。
注:方法重写时,方法签名必须与父类中的虚方法完全一致,否则重写不成功,其中包括“返回值”
Abstract注意
抽象类不能被实例化
如果一个类中有任何抽象成员,那么这个类也必须是抽象类abstract class
子类继承抽象类后,必须重写父类中的所有抽象成员,除非子类也是一个抽象类
抽象成员在抽象类中不能有任何实现。
象类中可以有抽象成员也可以有非抽象成员
父类指向子类时的方法调用(多态就是通过这个实现的)
* 首先添加需要的资源到Resources(方便稍后使用),这种方式可将图片、音频等资源直接编译到exe或dll文件中,将来程序发布时只需要一个可执行文件即可,无需发布所有图片、音频等其他资源。与web程序不同。
intern(string str)字符串优化方法 要在暂存池中搜索的字符串。
为什么要用数据库:我们平时把数据以文件的方式存放在硬盘里,但当数据量庞大的时候:文件大,操作效率很低下。所以,便有了很多种数据库软件(Mssql,Ora,DB2…),它们代替我们做数据文件的操作(mdf,ndf,ldf)并提供高效的存储和检索等操作。还提供了很多接口给其他程序语言调用。
用文件保存数据与用数据库的优劣:
高效维护大量数据-检索/增/删/改
处理各个表之间的关系
压缩表数据
安全
主键(PrimaryKey)
* 就是一个表中每个数据行的唯一标识。
* 主键有两种选用策略:业务主键和逻辑主键。业务主键是使用有业务意义的字段做主键,比如身份证号、银行账号等;逻辑主键是使用没有任何业务意义的字段做主键,完全给程序看的,业务人员不会看的数据。因为很难保证业务主键不会重复(身份证号重复)、不会变化(帐号升位),因此推荐用逻辑主键。
* 外键(ForeignKey)—记录表与表的关联
l 常用字段类型:bit(可选值0、1)、datetime、int、varchar、nvarchar(可能含有中文用nvarchar)
l Nvarchar(50)、Nvarchar(MAX)
l varchar、nvarchar 和char(n)的区别: char(n)不足长度n的部分用空格填充。Var:Variable,可变的。
SQL语句中字符串用单引号。
SQL语句是大小写不敏感的,不敏感指的是SQL关键字,字符串值还是大小写敏感的
* SQL主要分DDL(数据定义语言)和DML(数据操作语言)两类。Create Table、Drop Table、Alter Table等属于DDL,Select、Insert、Update、Delete等属于DML
数据库中,一个列如果没有指定值,那么值就为null,这个null和C#中的null,数据库中的null表示“不知道”,而不是表示没有因此select null+1结果是null,因为“不知道”加1的结果还是“不知道”。
TRUNCATE和DELETE有以下几点区别
1、TRUNCATE在各种表上无论是大的还是小的都非常快。如果有ROLLBACK命令DELETE将被撤销,而TRUNCATE则不会被撤销。
2、TRUNCATE是一个DDL语言,向其他所有的DDL语言一样,他将被隐式提交,不能对TRUNCATE使用ROLLBACK命令。
3、TRUNCATE将重新设置高水平线和所有的索引。在对整个表和索引进行完全浏览时,经过TRUNCATE操作后的表比DELETE操作后的表要快得多。
4、TRUNCATE不能触发任何DELETE触发器。
5、不能授予任何人清空他人的表的权限。
6、当表被清空后表和表的索引讲重新设置成初始大小,而delete则不能。
7、不能清空父表。
* 通配符过滤
通配符过滤关键字使用LIKE
单字符匹配的通配符为半角下划线“_”,它匹配单个出现的字符
多字符匹配的通配符为半角百分号“%”,它匹配任意次数(零或多个)出现的任意字符。
* [ ]
* 括号中所指定范围内的一个字符
* [^]
* 不在括号中所指定范围内的一个字符
多值处理:
* Delete T_Employee where FId in (21,22)
* 按照年龄进行分组统计各个年龄段的人数:SELECT FAge,Count(*) FROM T_Employee GROUP BY Fage
* 没有出现在GROUP BY子句中的列是不能放到SELECT语句后的列名列表中的 (聚合函数中除外)
SQL中使用is null、is not null来进行空值判断
在Where中不能使用聚合函数,必须使用Having,Having要位于Group By之后:
SELECT FAge,COUNT(*) AS 人数 FROM T_Employee
GROUP BY FAge
HAVING COUNT(*)>1
注意Having中不能使用未参与分组的列,Having不能替代where。作用不一样,Having是对组进行过滤。
限制结果集。返回第3行到第5行的数据
SELECT top 3 * FROM T_Employee
WHERE FNumber NOT IN (SELECT TOP 3 FNumber FROM T_Employee ORDER BY FSalary DESC)
ORDER BY FSalary DESC
( ROW_NUMBER 不能用在where子句中,所以将带行号的执行结果作为子查询,就可以将结果当成表一样用了):
SELECT * FROM
(
SELECT ROW_NUMBER() OVER(ORDER BY FSalary DESC) AS rownum,
FNumber,FName,FSalary,FAge FROM T_Employee
) AS a
WHERE a.rownum>=3 AND a.rownum<=5
* DISTINCT是对整个结果集进行数据重复处理的
Alter增加字段之后要关闭窗口重新打开才能看到新增加的列。
* 简单的结果集联合:
SELECT FNumber,FName,FAge FROM T_Employee UNION SELECT FIdCardNumber,FName,FAge FROM T_TempEmployee
* 基本的原则:每个结果集必须有相同的列数;每个结果集的列必须类型相容。
1.UNION合并两个查询结果集,并且将其中完全重复的数据行合并为一条
2.Union因为要进行重复值扫描,所以效率低,因此如果不是确定要合并重复行,那么就用UNION ALL
* 数字函数(*)
* ABS() :求绝对值。
* CEILING():舍入到最大整数 。3.33将被舍入为4、2.89将被舍入为3、-3.61将被舍入为-3。 Ceiling→天花板
* FLOOR():舍入到最小整数。3.33将被舍入为3、2.89将被舍入为2、-3.61将被舍入为-4。 Floor→地板。
* ROUND():四舍五入。舍入到“离我半径最近的数” 。Round→“半径”。Round(3.1425,2)。
* LEN() :计算字符串长度
* LOWER() 、UPPER () :转小写、大写
* LTRIM():字符串左侧的空格去掉
* RTRIM () :字符串右侧的空格去掉
LTRIM(RTRIM(' bb '))
* SUBSTRING(string,start_position,length)
* 日期函数
* GETDATE() :取得当前日期时间
* DATEADD (datepart , number, date ),计算增加以后的日期。参数date为待计算的日期;参数number为增量;参数datepart为计量单位,可选值见备注。DATEADD(DAY, 3,date)为计算日期date3天后的日期,而DATEADD(MONTH ,-8,date)为计算日期date8个月之前的日期
* DATEDIFF ( datepart , startdate , enddate ) :计算两个日期之间的差额。 datepart 为计量单位,可取值参考DateAdd。
* 统计不同工龄的员工的个数:
* select DateDiff(year,FInDate,getdate()),count(*) from T_Employee group by DateDiff(year,FInDate,getdate())
* DATEPART (datepart,date):返回一个日期的特定部分
类型转换函数
* CAST ( expression AS data_type)
* CONVERT ( data_type, expression)
* SELECT FIdNumber,
RIGHT(FIdNumber,3) as 后三位,
CAST(RIGHT(FIdNumber,3) AS INTEGER) as 后三位的整数形式,
CAST(RIGHT(FIdNumber,3) AS INTEGER)+1 as 后三位加1,
CONVERT(INTEGER,RIGHT(FIdNumber,3))/2 as 后三位除以2
ISNULL(expression,value) :
如果expression不为空则返回expression,否则返回value
* CASE函数用法1
* CASE expression
WHEN value1 THEN returnvalue1
WHEN value2 THEN returnvalue2
WHEN value3 THEN returnvalue3
ELSE defaultreturnvalue
END
* 例子SELECT
* SELECT FName,
(CASE FLevel WHEN 1 THEN 'VIP客户'
WHEN 2 THEN '高级客户'
WHEN 3 THEN '普通客户'
ELSE '客户类型错误'
END) as FLevelName
FROM T_Customer
* CASE函数用法2
CASE
WHEN condition1 THEN returnvalue1
WHEN condition 2 THEN returnvalue2
WHEN condition 3 THEN returnvalue3
ELSE defaultreturnvalue
END
相当于if…else…else….
SELECT FName, FWeight,
(CASE
WHEN FWeight<40 THEN ‘瘦瘦'
WHEN FWeight>50 THEN ‘肥肥'
ELSE 'ok'
END) as isnormal
FROM T_Person
* 子查询
* 将一个查询语句做为一个结果集供其他SQL语句使用,就像使用普通的表一样,被当作结果集的查询语句被称为子查询。
声明局部变量
DECLARE @变量名 数据类型
DECLARE @bookName varchar(20)
DECLARE @bId int
赋值
SET @变量名 =值 --set用于普通的赋值
SELECT @变量名 = 值 --用于从表中查询数据并赋值
变量分为:
* 局部变量:
局部变量必须以标记@作为前缀 ,如@Age int
局部变量:先声明,再赋值
* 全局变量(系统变量):
全局变量必须以标记@@作为前缀,如@@version
全局变量由系统定义和维护,我们只能读取,不能修改全局变量的值
* 事务
* 指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)--也就是由多个sql语句组成,必须作为一个整体执行
* 语法步骤:
开始事务:BEGIN TRANSACTION
事务提交:COMMIT TRANSACTION
事务回滚:ROLLBACK TRANSACTION
* 判断某条语句执行是否出错:
全局变量@@ERROR;
@@ERROR只能判断当前一条T-SQL语句执行是否有错,为了判断事务中所有T-SQL语句是否有错,我们需要对错误进行累计;
例:SET @errorSum=@errorSum+@@error
* 存储过程---就像数据库中运行方法(函数)
* 系统存储过程
* 由系统定义,存放在master数据库中
* 名称以“sp_”开头或”xp_”开头
l 系统存储过程
sp_databases |
列出服务器上的所有数据库。 |
sp_renamedb |
更改数据库的名称 |
sp_helpindex |
查看某个表的索引 |
sp_password |
添加或修改登录帐户的密码。 |
* 创建存储过程
* 定义存储过程的语法
CREATE PROC[EDURE] 存储过程名
@参数1 数据类型 = 默认值 OUTPUT,
@参数n 数据类型 = 默认值 OUTPUT
AS
SQL语句
* 参数说明:
参数可选
参数分为输入参数、输出参数
输入参数允许有默认值
* EXEC 过程名 [参数]
无参数的存储过程调用:
* Exec pro_GetAge
有参数的存储过程两种调用法:
* EXEC proGetPageData 60,55 ---按次序
* EXEC proGetPageData @labPass=55,@writtenPass=60 --参数名
参数有默认值时:
* EXEC proGetPageData --都用默认值
* EXEC proGetPageData 1 --页容量(@pageSize)默认值
* EXEC proGetPageData 1,5 --不用默认值
* 触发器是一种特殊类型的存储过程,它不同于前面介绍过的一般的存储过程。
* 一般的存储过程通过存储过程名称被直接调用,而触发器主要是通过事件进行触发而被执行。
* 常见的触发器有三种:分别应用于Insert , Update , Delete 事件
CREATE TRIGGER triggerName ON Table
for UPDATE|INSERT|DELETE
AS
begin
…
end
Ado.net
Connection 类
和数据库交互,你必须连接它。连接帮助指明数据库服务器、数据库名字、用户名、密码,和连接数据库所需要的其它参数。Connection对象会被Command对象使用,这样就能够知道是在哪个数据源上面执行命令。
与数据库交互的过程意味着你必须指明想要执行的操作。这是依靠Command对象执行的。你使用Command对象来发送SQL语句给数据库。Command对象使用Connection对象来指出与哪个数据源进行连接。你能够单独使用Command对象来直接执行命令,或者将一个Command对象的引用传递给DataAdapter,它保存了一组能够操作下面描述的一组数据的命令。
Command对象
成功于数据建立连接后,就可以用Command对象来执行查询、修改、插入、删除等命令; Command对象常用的方法有ExecuteReader方法、ExecuteScalar()方法和ExecuteNonQuery()方法;插入数据可用ExecuteNonQuery()方法来执行插入命令。
DataReader类
许多数据操作要求你只是读取一串数据。DataReader对象允许你获得从Command对象的SELECT语句得到的结果。考虑性能的因素,从DataReader返回的数据都是快速的且只是
ADO.NET的组成
l
l ADO:ActiveX Data Objects
l
l ADO.Net中提供了对各种不同数据库的统一操作接口。
Connection 类
和数据库交互,你必须连接它。连接帮助指明数据库服务器、数据库名字、用户名、密码,和连接数据库所需要的其它参数。Connection对象会被Command对象使用,这样就能够知道是在哪个数据源上面执行命令。
与数据库交互的过程意味着你必须指明想要执行的操作。这是依靠Command对象执行的。你使用Command对象来发送SQL语句给数据库。Command对象使用Connection对象来指出与哪个数据源进行连接。你能够单独使用Command对象来直接执行命令,或者将一个Command对象的引用传递给DataAdapter,它保存了一组能够操作下面描述的一组数据的命令。
Command对象
成功于数据建立连接后,就可以用Command对象来执行查询、修改、插入、删除等命令; Command对象常用的方法有ExecuteReader方法、ExecuteScalar()方法和ExecuteNonQuery()方法;插入数据可用ExecuteNonQuery()方法来执行插入命令。
DataReader类
许多数据操作要求你只是读取一串数据。DataReader对象允许你获得从Command对象的SELECT语句得到的结果。考虑性能的因素,从DataReader返回的数据都是快速的且只是“向前”的数据流。这意味着你只能按照一定的顺序从数据流中取出数据。这对于速度来说是有好处的,但是如果你需要操作数据,更好的办法是使用DataSet。
DataSet对象
DataSet对象是数据在内存中的表示形式。它包括多个DataTable对象,而DataTable包含列和行,就象一个普通的数据库中的表。你甚至能够定义表之间的关系来创建主从关系(parent-child relationships)。DataSet是在特定的场景下使用――帮助管理内存中的数据并支持对数据的断开操作的。DataSet是被所有Data Providers使用的对象,因此它并不像Data Provider一样需要特别的前缀。
DataAdapter类
某些时候你使用的数据主要是只读的,并且你很少需要将其改变至底层的数据源。同样一些情况要求在内存中缓存数据,以此来减少并不改变的数据被数据库调用的次数。DataAdapter通过断开模型来帮助你方便的完成对以上情况的处理。当在一单批次的对数据库的读写操作的持续的改变返回至数据库的时候,DataAdapter 填充(fill)DataSet对象。DataAadapter包含对连接对象以及当对数据库进行读取或者写入的时候自动的打开或者关闭连接的引用。另外,DataAdapter包含对数据的SELECT、INSERT、UPDATE和DELETE操作的Command对象引用。你将为DataSet中的每一个Table都定义DataAadapter,它将为你照顾所有与数据库的连接。所有你将做的工作是告诉DataAdapter什么时候装载或者写入到数据库。
DataTable类
DataTable 是一个数据网格控件,理解成一张表就可以了。
DataTable的实例化以及添加列:
DataTable dt = new DataTable();
dt.Columns.Add("ID");
dt.Columns.Add("Name");
DataRow dr = dt.NewRow();
object[] objs = { 1, "Name" };
dr.ItemArray = objs;
dt.Rows.Add(dr);
this.dataGridView1.DataSource = dt;
连接数据库
string dataDir = AppDomain.CurrentDomain.BaseDirectory;
if (dataDir.EndsWith(@"\bin\Debug\")
|| dataDir.EndsWith(@"\bin\Release\"))
{
dataDir = System.IO.Directory.GetParent(dataDir).Parent.Parent.FullName;
AppDomain.CurrentDomain.SetData("DataDirectory", dataDir);
}
Asp.net 连接 App_Data文件夹内数据库:
Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Test.mdf;Integrated Security=True;User Instance=True
* 执行简单的Insert语句
* SqlCommand表示向服务器提交的一个命令(SQL语句等) , CommandText属性为要执行的SQL语句,ExecuteNonQuery方法执行一个非查询语句(Update、Insert、Delete等)
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "Insert into T_Users(UserName,Password) values('admin','888888')";
cmd.ExecuteNonQuery();
}
* ExecuteNonQuery返回值是执行的影响行数
* SqlCommand的ExecuteScalar方法用于执行查询,并返回查询所返回的结果集中第一行的第一列,因为不能确定返回值的类型,所以返回值是object类型。
* cmd.CommandText = "select count(*) from T_Users";
int i = Convert.ToInt32(cmd.ExecuteScalar())
* cmd.CommandText = "select getdate()";
DateTime dt = Convert.ToDateTime(cmd.ExecuteScalar());
* 执行有多行结果集的用ExecuteReader
SqlDataReader reader = cmd.ExecuteReader();...
while (reader.Read())
{ Console.WriteLine(reader.GetString(1));
}
* reader的GetString、GetInt32等方法只接受整数参数,也就是序号,用GetOrdinal方法根据列名动态得到序号
* DataReader 的主要成员
HasRows 是否返回了结果
* Read 前进到下一行记录
* 防范注入漏洞攻击的方法:不使用SQL语句拼接,通过参数赋值
* 查询参数
* SQL语句使用@UserName表示“此处用参数代替”,向SqlCommand的Parameters中添加参数
* cmd.CommandText = "select * from T_Users where UserName=@UserName and Password=@Password";
* cmd.Parameters.Add(new SqlParameter("UserName","admin"));
* cmd.Parameters.Add(new SqlParameter("Password",password));
* 参数在SQLServer内部不是简单的字符串替换,SQLServer直接用添加的值进行数据比较,因此不会有注入漏洞攻击
l DataSet的更新
l 通过DataRow的RowState可以获得行的状态(删除、修改、新增等);调用DataSet的GetChanges()方法得到变化的结果集,降低传递的资源占用。
* 只要在类型后加?就构成了可空的数据类型,比如int?、bool?,这样int? i=null 就可以了。解决数据库中int可以为null,而C#中int不能为null的问题。
* 判断可空类型是否为空,i==null或者i.HasValue;得到可空变量的值,
接口相当于没有方法实现的抽象类。
public interface Flyable
{
void Flay();
}
接口方法不要public。
常用系统接口
using,实现了IDisposable接口的对象可以使用using进行资源声明,出了using的作用域以后自动调用Dispose方法。 Dispose和Close的区别:实现了IDisposable接口必须定义Dispose方法,但不一定有Close方法,很多Dispose的实现都是调用Close方法。SqlConnection Close以后还能重新Open,但是Dispose以后就不能再用。
foreach:实现了IEnumerable接口的对象都可以使用foreach进行遍历。
列表
ArrayList,可以看做是动态的数组。Add、Clear、Contains、Count、Remove、RemoveAt、ToArray(转换,再没关系)、索引器
- list1.AddRange(strs)//将数组的引用加入list1
C#中所有的数组类型int[]、string[]等都是继承自Array类。list1.AddRange(strs)
集合,ArrayList、HashSet、Hashtable、Dictionary等都可以叫做集合类。实现了IEnumerable(getEnumerator())、IEnumerable<T>的接口都可以使用foreach进行遍历。
泛型的ArrayList,所以就有了List<T>。List<int> 除此之外并无不同,<int>表示List中放的数据类型是int类型的,因为有声明类型时的约定,因此所有方法的参数、返回值都是确定类型的了。
HashSet<T>:不能盛放重复的数据,重复的数据只保留一份。Add(T value)添加元素;Contains(T value)判断是否存在元素,HashSet使用了和Dictionary类似的算法,因此Contains方法效率非常高,时间复杂度为O(1)。
(*)Stack<T>,栈,先入后出,Push(压栈)、Pop(出栈)。
(*)Queue<T>,队列,先入先出:Enqueue(入队)、Dequeue(出队)
三层架构
模型层Model;数据访问层DAL(Data Access Layer);业务逻辑层BLL(business logic layer )。实体类就是Model;对数据进行操作的代码写在DAL中,一般就是SQL语句,DAL只有对数据的操作,没有“如果金额大于20则不能删除”这样的逻辑;BLL调用DAL中的代码进行逻辑操作,比如“如果金额大于20则不能删除”。SQL语句一般只应该出现在DAL中。
三层:UI(界面,User Interface)、BLL、DAL。Model是在三层之间进行数据传递的。UI层调用BLL、BLL调用DAL,数据用Model传递,UI不能直接调用DAL。
基础知识:Path.Combine()可以进行两个路径的拼接,省得自己处理\的问题;Directory.CreateDirectory()如果文件夹不存在则创建;File.WriteAllText将字符串写入文本文件;StringBuilder可以用来更高效的进行字符串拼接,AppendLine方法会自动添加换行。
MD5算法是一种散列(hash)算法(摘要算法,指纹算法),不是一种加密算法(易错)。任何长度的任意内容都可以用MD5计算出散列值。
MD5算法不可逆,也就是只能得到内容对应的MD5值,无法由MD5值反推内容。对不不同的内容产生相同MD5值的概率非常非常非常低!
迭代式开发,不是所有功能都一上来就全部写好,而是添砖加瓦
程序处理Excel的技术
NPOI、MyXls等,NPOI能够分析Excel文件的格式,能够进行常用Excel操作,不依赖于Excel,节省资源,没有安全性、性能的问题,在ASP.net中用最合适。只能处理xls格式文件、不能处理xlsx这样的新版本Excel文件格式。处理xlsx还要用OpenXML。
NPOI起步
1、读取
using (FileStream stream = new FileStream(@"c:\客户资料.xls", FileMode.Open, FileAccess.Read))
{
HSSFWorkbook workbook = new HSSFWorkbook(stream);
MessageBox.Show(workbook.GetSheetName(0));
}
2、遇到错误别慌,仔细看错误信息。可能遇到的问题:文件被其他进程占用。
3、NPOI处理WPS生成的XLS有问题。
? FTP端口:21;Http端口:80
程序操作FTP
(*).Net中内置的操作FTP的类有:WebClient、FtpWebRequest。WebClient用起来简单,但是只能上传、下载。 FtpWebRequest 比较强大,WebClient内部就是调用FtpWebRequest实现的,如果要实现遍历ftp文件、创建ftp文件夹等就要用FtpWebRequest 。
(*)WebClient也可以下载Http网页、上传Http文件,后面站内搜索、采集器项目中还将会用到。
开源的FTPClient.cs。测试上传和下载。
TreeView控件
– 向根节点下增加子节点:treeView.Nodes.Add,它的返回值就是创建的节点对象。treeView.Nodes代表根节点的所有子节点。
– 向TreeNode增加子节点,treeNode.Nodes.Add,它的返回值就是创建的节点对象。treeNode.Nodes代表节点的所有子节点。