总结:推荐视频:刘铁锰:C#入门:https://www.bilibili.com/video/av7606481/
中国MOOC 搜唐大仕C# (感觉讲的比较浅,可以捡重点快速浏览,重点看7和11章)
微软官方网站:https://docs.microsoft.com/zh-cn/
入门可以看《C#图解教程》,讲的比较全面,过度到《C#高级编程》和《深入理解C#》。
学习C#前提是下载好Visual Studio,配合书上的代码进行动手练习,动手非常重要。
学习路线:https://www.cnblogs.com/wangsea/p/9413600.html
唐大仕视频笔记:
第一课
1.用VS设计winform
2.对象三要素
第二课 C#语言基础
数组是引用类型,数组定义和赋值需分开进行,new一个a,指向一个空间,对该空间赋值
静态初始化:在定义数组的同时为数组元素分配空间并赋值
int[] a={3,9,8};
age是变量,ages是数组名
作业练习:
第三课 面向对象的C#语言
1.索引器
属性和索引就是对字段和方法的扩展,在一定意义上,属性是对字段的访问,索引器是对数组的访问,属性可以实现只读或只写而字段不能,属性的set方法可以对用户指定的值,进行有效检查,确保只有正确的状态才会得到设置
2.类的继承
使用冒号,c#采用单继承,子类subclass,父类baseclass
class Subclass:BaseClass{
...
}
- 子类自动地从父类继承所有
- 除了继承父类成员,子类还可以:添加新成员,隐藏或修改父类的成员
使用base可以调用父类的字段或方法
is 运算符
if(p is Person):判断一个对象是不是某个类(及其子类)的实例
3.修饰符
访问控制符
protected:逻辑角度 internel:物理角度,是否在一个文件
static:static的字段、方法、属性是属于整个类的
- static方法中,不能访问实例变量,和this相对立
- 调用static方法时,直接用类名访问
- static变量可以用来表示“全局变量”
struct是值类型,不能被继承
4.结构
struct是值类型
实例化使,使用new,但与引用型变量的内存是不同的
- Point p=new Point(100,80);
值类型变量在赋值时,实行的是字段的copy
- Point p1,p2;
- p1=p2;
第四课 高级特性
首先,委托的关键字是Delegate ,委托是和类同级别的对象,委托应该声明成Public。下面我们先来看下这段代码:
public delegate int GreetingDelegate(int a ,int b);//定义委托
static void Main(string[] args)
{
Console.WriteLine(pro(3,4,add));
}
public static int pro(int x, int y, GreetingDelegate Gd )
{
return Gd(x,y);
}
public static int add(int x,int y) {
return x + y;
}
上面代码首先,声明一个委托变量,然后再把委托变量作为Pro里面参数 最后返回委托的方法
我们可以得出结论 :
1.委托可以把方法当作参数一样传递
2.委托方法的参数定义能够确定方法可以代表的方法种类
委托出了上面的调用方式外还有一种调用方式:
public delegate int GreetingDelegate(int a ,int b);//定义委托
static void Main(string[] args)
{
GreetingDelegate d1;
d1 =pro;
d1 += add;
Console.WriteLine( d1(3, 4));
}
public static int pro(int x, int y)
{
return x-y;
}
public static int add(int x,int y) {
return x + y;
}
这段代码也是先声明一个委托变量 然后把pro方法赋值给d1最后绑定add方法并调用
结论:
1.我们可以把方法赋值给委托变量,委托变量可以绑定方法(第一次d1=pro是赋值,第二次d1+=add才是绑定方法 而我们调用的d1(3,4)就相当于调用的add(3,4),如果第一次就用+=将出现为赋值对象)
2.委托对象+=方法 (绑定方法)
委托对象-=方法(取消绑定方法)
3.同一委托对象可以绑定多个方法,并可以依次执行所有绑定方法
委托声明在类外面
1.委托是对函数原型的包装
- 委托的声明
public delegate double MyDelegate(double x);
2.委托的实例化
MyDelegated d2=new MyDelegate(obj.myMethod);
3.委托的调用
委托变量名(参数列表)
d2(8.9);
2.委托的合并
多播委托是指在一个委托中注册多个方法
一个委托实例可以“包含”多个函数
用运算符+- += -=动态地增减其中的函数,
3.事件
例子:(没明白)
public delegate void DownloadStartHandler(object sender, DownloadStartEventArgs e); //声明委托
public delegate void DownloadStartHandler(object sender, DownloadStartEventArgs e); //声明委托
public class DownloadStartEventArgs
{
public string Url{ get{ return _url;} set{ _url=value;} }
private string _url;
public DownloadStartEventArgs( string url ){ this._url = url; }
}
public class Crawler
{
public event DownloadStartHandler DownloadStart; // 声明事件
public void Craw()
{
while( true )
{
string url = GetNextUrl();
if( url == null ) break;
long size = GetSizeOfUrl( url );
if( DownloadStart != null ) //下载开始的事件发生
{
DownloadStart( this, new DownloadStartEventArgs(url));
}
}
class Test
{
static void Main()
{
Crawler crawler = new Crawler("Crawer101", "https://www.pku.edu.cn");
crawler.DownloadStart += new DownloadStartHandler( ShowStart ); //注册事件
crawler.Craw();
}
}
static void ShowStart(object sender, DownloadStartEventArgs e){
Console.WriteLine( (sender as Crawler).Name + "开始下载" + e.Url );
}
4.Lambda表达式
泛型List——避免强制转换
Lamda表达式:直接用(参数)=> {语句或表达式}
例:new Thread(()=>{ ... }).Start();
5.异常处理
- 捕获异常
try{}
catch{Exception e}
finally{}
2.抛出异常
if( xxx) throw new someException(信息)
第五章 基础类及常用算法
String 内容不可变,StringBuilder内容可变
StringBuilder类比string类在循环中执行更快
集合类
- 数组列表ArrayList ,相当于动态数组
- 哈希表 Hashtable,用[ ]进行访问,表示获取,增加,删除,修改,提示:用于查询时,比线性搜索的效率要高,可用于程序优化
- 使用foreach访问数组及集合
第6章 流、文件
- 文本文件的操作:建立StreamReader,StreamWriter对象
- 二进制文件操作:FileStream
程序调试的基本手段:
- 断点:左边单机
- 跟踪:看程序流程 F10或F11
- 监视:查看变量,鼠标指向它,或点右键,添加监视
先打断点,鼠标停到变量会显示变量值,点F10或F11跟踪流程
第7章 Windows窗体
布局与事件
窗体布局实例参考My_Explorer_src
控件
掩码文本框:显示需要一定条件的文本框
FlowLayoutPanel:流式布局控件,添加到它上面的控件会按设定顺序依次排列,并且不支持拖拽到特定位置
Panel:panel为普通容器,没有布局功能,可以拖控件到任意位置
SplitContainer:使用 SplitContainer 控件,可以创建复合的用户界面(通常,在一个面板中的选择决定了在另一个面板中显示哪些对象)。这种排列对于显示和浏览信息非常有用。拥有两个面板使您可以聚合不同区域中的信息,并且用户可以轻松地使用拆分条(也称为“拆分器”)调整面板的大小。
项目右键添加用户控件窗体,处理Paint事件
第8章 绘图及图像
1.绘图基础GDI+
2.绘图对象及绘图方法
pen:画笔
brush:画刷
3.绘件的重绘和双缓冲
framework3以上版本有doublebuffer双缓冲,减少闪烁
第9章 文本处理及正则表达式
第10章 网络信息获取及xml处理
1.网络信息获取的基本方法
查看服务端和浏览器通讯信息:http://www.fidder2.com/ Chrome/FireFox等浏览器按F12,network中查看
使用System.Web提供支持浏览器/服务器通讯的类和接口
WebClient类
2.XML基本操作
Xpath是对xml进行查询的表达式
第11章 多线程与异步编程
1.线程及其控制
线程的同步:
使用join方法:将单独的执行线程合并成一个线程
Thread.Join() 在MSDN中的解释:Blocks the calling thread until the thread represented by this instance terminates.(在此实例表示的线程终止前,阻止调用线程。)
static void Main(string[] args)
{
Thread thread1 = new Thread(new ThreadStart(Test1));
thread1.Start();
thread1.Join();
Thread thread2 = new Thread(new ThreadStart(Test2));
thread2.Start();
thread2.Join();
Console.WriteLine("finished.");
Console.Read();
}
static void Test1()
{
Console.WriteLine("t1 " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
Thread.Sleep(500);
Console.WriteLine("t1 " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
Thread.Sleep(500);
Console.WriteLine("t1 " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
Thread.Sleep(500);
Console.WriteLine("t1 " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
Thread.Sleep(500);
Console.WriteLine("t1 " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
Thread.Sleep(500);
Console.WriteLine("t1 " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
Thread.Sleep(500);
Console.WriteLine("t1 " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
Thread.Sleep(500);
Console.WriteLine("t1 " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
Thread.Sleep(500);
Console.WriteLine("t1 " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
Thread.Sleep(500);
Console.WriteLine("t1 " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
Thread.Sleep(500);
}
static void Test2()
{
Console.WriteLine("t2 " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
Thread.Sleep(500);
Console.WriteLine("t2 " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
Thread.Sleep(500);
Console.WriteLine("t2 " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
Thread.Sleep(500);
Console.WriteLine("t2 " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
Thread.Sleep(500);
Console.WriteLine("t2 " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
Thread.Sleep(500);
Console.WriteLine("t2 " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
Thread.Sleep(500);
Console.WriteLine("t2 " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
Thread.Sleep(500);
Console.WriteLine("t2 " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
Thread.Sleep(500);
Console.WriteLine("t2 " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
Thread.Sleep(500);
Console.WriteLine("t2 " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
Thread.Sleep(500);
}
thread1 启动后,调用 Join() 方法,直到 thread1 的任务结束,才轮到 thread2 启动,然后 thread2 也开始任务。实例中,两个线程就按着严格的顺序来执行了。如果 thread2 的执行需要依赖于 thread1 中的完整数据的时候,这种方法就可以很好的确保两个线程的同步性。
lock语句使同一时间只有一个线程可以执行对象或表达式
2.并行编程(多个CPU同时执行任务)
3.异步编程
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
/// <summary>
/// 异步调用方法总结:
/// 1.BeginEnvoke EndEnvoke
/// 当使用BeginInvoke异步调用方法时,如果方法未执行完,EndInvoke方法就会一直阻塞,直到被调用的方法执行完毕
/// </summary>
class Async1
{
public delegate int FooDelegate(string s);
static void Main(string[] args)
{
Console.WriteLine("主线程"+Thread.CurrentThread.ManagedThreadId);
FooDelegate fooDelegate = Foo;
IAsyncResult result= fooDelegate.BeginInvoke("Hello World.", null, null);
Console.WriteLine("主线程继续执行...");
//当使用BeginInvoke异步调用方法时,如果方法未执行完,EndInvoke方法就会一直阻塞,直到被调用的方法执行完毕
int n = fooDelegate.EndInvoke(result);
Console.WriteLine("回到主线程"+Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("结果是"+n);
Console.ReadKey(true);
}
public static int Foo(string s)
{
Console.WriteLine("函数所在线程"+Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("异步线程开始执行:"+s);
Thread.Sleep(1000);
return s.Length;
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
/// <summary>
/// 异步调用方法总结:
/// 回调
/// 异步线程在工作结束后会主动调用我们提供的回调方法,并在回调方法中做相应的处理,例如显示异步调用的结果。
/// </summary>
class Program
{
public delegate void FooDelegate(string s);
static void Main(string[] args)
{
Console.WriteLine("主线程."+Thread.CurrentThread.ManagedThreadId);
FooDelegate fooDelegate = Foo;
fooDelegate.BeginInvoke("Hello world.",
FooComepleteCallback, fooDelegate);
Console.WriteLine("主线程继续执行..."+Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("Press any key to continue...");
Console.ReadKey(true);
}
public static void Foo(string s)
{
Console.WriteLine("函数当前线程:"+Thread.CurrentThread.ManagedThreadId);
Console.WriteLine(s);
Thread.Sleep(1000);
}
//回调方法要求
//1.返回类型为void
//2.只有一个参数IAsyncResult
public static void FooComepleteCallback(IAsyncResult result)
{
Console.WriteLine("回调函数所在线程:"+Thread.CurrentThread.ManagedThreadId);
(result.AsyncState as FooDelegate).EndInvoke(result);
Console.WriteLine("回调函数线程结束." + result.AsyncState.ToString());
}
}
讲await和async:https://www/cnblogs.com/landeanfen/p/4734252.html
1.凡是使用await关键字的方法,都必须打上async标记。
2.async表示方法内有异步方法,调用async方法,会立刻另起线程执行。
3.await只是显示等待线程结束。await表示等待异步方法执行完,并取返回值。
4.所有的async方法返回类型必然是Task或Task<T>,这是异步处理的基础
5.在async方法中遇到await关键字后,当前线程立即返回(到调用方),继续之前的处理逻辑,await关键字之后的代码逻辑,交由新线程处理,当新线程处理完成,可以从新线程返回处理结果到调用线程当中,结束等待
using System;
using System.Threading;
using System.Threading.Tasks;
class AsyncSimple1
{
Task<double> FacAsync(int n)
{
return Task<double>.Run( ()=>{
double s = 1;
for(int i=1; i<n; i++) s = s*i;
return s;
});
}
async void Test()
{
// 调用异步方法
double result = await FacAsync(10);
Console.WriteLine( result); //想想这句在哪个线程
}
static void Main()
{
new AsyncSimple1().Test();
Console.ReadKey();
}
}
第12章 访问数据库
由于Access数据库用得较少,现在用SQLite数据库的人越来越多。SQLite是一个轻量级的桌面数据库,用一个文件来存储所有的表,使用起来十分方便。
https://sqlite.org/ 是其官网,可以下载Sqlite。还可以下载一些图形化的客户端,如https://sqliteexpert.com/v4/SQLiteExpertPersSetup64.exe 还有Navicat等。
如果用Visual Studio,为了访问SQLite,需要下载System.Data.SQLite, 见https://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki ,
不过,可以直接从VisualStudio中使用 工具--NuGet包管理--项目的NuGet包管理工具,从搜索中搜索 SQLite,然后点下载安装。
安装后, using System.Data.SQLite 就可以
using System.Data.SQLite;
public void Demo()
{
//如果不存在,则创建一个空的数据库,
if(!System.IO.File.Exists("MyDatabase.sqlite"))
SQLiteConnection.CreateFile("MyDatabase.sqlite");
//创建一个连接
SQLiteConnection m_dbConnection = new SQLiteConnection("Data Source=MyDatabase.sqlite;Version=3;");
m_dbConnection.Open();
//创建一个数据表
string sql = "create table book (title varchar(20), author varchar(10), pages int)";
SQLiteCommand command = new SQLiteCommand(sql, m_dbConnection);
try
{
command.ExecuteNonQuery();
}
catch(Exception ex)
{
Console.WriteLine(ex);
}
//插入一些记录
sql = "insert into book (title, author, pages) values ('C#程序设计教程', '唐大仕', 570)";
command = new SQLiteCommand(sql, m_dbConnection);
command.ExecuteNonQuery();
sql = "insert into book (title, author, pages) values ('Java程序设计', '唐大仕', 390)";
command = new SQLiteCommand(sql, m_dbConnection);
command.ExecuteNonQuery();
sql = "insert into book (title, author, pages) values ('Visual C++.NET程序设计', '唐大仕,刘光', 410)";
command = new SQLiteCommand(sql, m_dbConnection);
command.ExecuteNonQuery();
//使用sql查询语句,并显示结果
sql = "select * from book order by pages desc";
command = new SQLiteCommand(sql, m_dbConnection);
SQLiteDataReader reader = command.ExecuteReader();
while (reader.Read())
Console.WriteLine("书名: " + reader["title"] + "\t页数: " + reader["pages"]);
//关闭连接
m_dbConnection.Close();
Console.ReadLine();
}
Mysql:开源 Oracle:大中型企业在用