文章目录
01 IP地址解析
问题与解决
-
程序实现思路:先实现对一个IP地址的解析,再加入循环。相关参数由用户输入,做好界面与后台的连接,完善程序健壮性。
-
问题1:错误lable提示出现之后就无法消失。
原因:最初lable背景白色无内容,在后台只在处理异常处设置改变颜 色和content。
解决:改用控件的显示和隐藏,并在每次开始扫描时隐藏。 -
问题2:stopwatch 不会
解决:查找资料解决 -
问题3:输入很多正确的IP却触发异常处理“IP地址错误”
原因:根据结果触发的异常处理检查try语句块,找到获取主机名的代码也在里面。
解决:分开异常处程序
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net;
using System.Diagnostics;
namespace testch01
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
lb.Visibility = Visibility.Hidden;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
lb.Visibility = Visibility.Hidden;
string strqz = qz.Text;
string strqsz = qsz.Text;
string strzzz = zzz.Text;
string strip;
IPAddress ip1, ip2;
if(!(IPAddress.TryParse(strqz + strqsz,out ip1)&& IPAddress.TryParse(strqz + strzzz, out ip2)))
{
lb.Content = "IP地址有错,请更正 1812030065 李诗雨";
lb.Visibility = Visibility.Visible;
return;
}
int n = int.Parse(strzzz) - int.Parse(strqsz) + 1;
if (n <= 1)
{
lb.Content = "起始值终止值有误";
lb.Visibility = Visibility.Visible;
return;
}
for (int i = 0; i < n; i++)
{
strip = strqz + (int.Parse(strqsz) + i).ToString();
IPAddress ip = IPAddress.Parse(strip);
scan(ip);
}
}
public void scan(IPAddress ip)
{
string hostname;
Stopwatch watch = new Stopwatch();
watch.Start();
IPHostEntry host = Dns.GetHostEntry(ip);
try
{
hostname = host.HostName.ToString();
}
catch (Exception)
{
hostname = "不能获取";
}
watch.Stop();
long ms = watch.ElapsedMilliseconds;
tb.Text += "扫描地址: " + ip + " 扫描时间: " + ms + "毫秒" + " 主机DNS名称:" + hostname + "\n";
}
}
}
02 任务管理器
实验要求
创建一个任务管理器,按下start显示当前电脑的进程及相关信息。选中一个进程结束进程,并且页面得到刷新。
界面设计
在xaml编辑器里面双击Grid (选中),在右侧属性栏里搜索Row definitions ,添加三个行元素,直接在设计界面调每行的高度。
在添加的控件里加上 Grid.Row=“0” ,行的索引是从0开始,实际上把控件拖到那个位置就会自动添加 Grid.Row=""。
中间放Data Grid。
最后一行,放俩按钮,用stack panel做容器,同理直接拖放。选中stack panel在其属性的orientation 设置水平显示horizontal。选中button,调整margin(外间距,即和其他控件的距离)
程序
思路:
- 创建方法将process获取的进程信息绑定到DataGrid,涉及进程获取,对象转化,绑定。并把方法绑定到start button
- 注意获取信息的格式化表示,以及一些因为访问权限无法获取要异常处理(filename,startTime)
- 要结束特定的进程就要获取选中的DataGrid的item,可以根据意思来找到方法,根据方法写数据类型。用进程来调用结束进程,注意异常处理。
- 刷新:每次结束一个进程之后要通过获取进程信息刷新一次。
- DataGrid 的数据源一般是一个以对象为元素的列表,虽然数组也可以但是在这里因为获取的进程数目不确定,而一般数组定义时要定义好长度。
它的列会根据传入数据源列表的对象的成员自动生成列,但是名字是成员名。如果想要更改为中文名。在xaml选中DataGrid,属性搜索columns,取消勾选auto generatecolumn(保持勾选,会在创建列后面继续生成列)点columns添加text类型的,添加项右边的属性header是标题,绑定单元格,数据类型选数据上下文,路径写对应数据元素成员名。
代码
中间start button 部分注释掉的是写按文件路径来启动程序。。。。学的浅,也没查到,暂时先放在这里
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ch03
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
//数据源
List<OneProcessData> list=new List<OneProcessData>();
/// <summary>
/// 获取进程信息,并放入DataGrid
/// </summary>
public void GetProcessData()
{
//更新
list.Clear();
this.DataGrid1.ItemsSource = null;
//获取
Process[] processes = Process.GetProcesses();
//转化
foreach (Process item in processes)
{
OneProcessData data = new OneProcessData();
data.id = item.Id;
data.name = item.ProcessName;
data.totalMemory = string.Format("{0,10:0} KB", item.WorkingSet64 / 1024d);
try
{
data.startTime = item.StartTime.ToString("G");
data.filename = item.MainModule.FileName;
}
catch (Exception)
{
data.startTime = "";
data.filename = "";
}
list.Add(data);
}
//绑定
this.DataGrid1.ItemsSource = list;
}
private void Button_Click_start(object sender, RoutedEventArgs e)
{
if (textbox.Text != "")// "" 不等于 null
{
string startinfo = textbox.Text;
Process p = new Process();
try
{
Process.Start(startinfo);
}
catch (Exception)
{
MessageBox.Show("error");
}
}
GetProcessData();
}
private void Button_Click_stop(object sender, RoutedEventArgs e)
{
this.Cursor = Cursors.Wait;//显示等待光标
//选中行
var temp = DataGrid1.SelectedItem; //返回object类型
//访问temp的成员并没有找到应有的数据,即object类型会隐藏成员
//类型转化
OneProcessData data = temp as OneProcessData;
try
{
Process my = Process.GetProcessById(data.id);
my.Kill();
}
catch (Exception)
{
MessageBox.Show("error");
}
GetProcessData();
this.Cursor = Cursors.Arrow;// 显示箭头
}
}
public class OneProcessData
{
//DataGird 识别不了字段必须是属性,并用此AutoGenrateColumn
//public int id;
//public string name;
public int id { get; set; }
public string name { get; set; }
public string totalMemory { get; set; }
public string startTime { get; set; }
public string filename { get; set; }
}
}
启动或结束进程好像只能启动或结束notepad
遇到的问题与解决
- 问题:名字后面的几列都显示是方框,也不显示异常处理赋值
分析:一般这种看起来不应该发生的错误都是命名错误或者是属性错误
解决:列属性选错了改回text型 - 问题:StartTime = p.StartTime.ToString(“yyyy-M-d HH:mm:ss”) 这个时间格式在我这个环境不能用
*解决:就找了个简单能用的 StartTime = p.StartTime.ToString(“G”) 结果是yyyy/m/d hh:mm:ss
DateTime日期格式化 - 问题:本来是要写一个根据路径来启动进程的。。。。主要是每找到相关内容
解决:最后就做了个简单的根据名称来启动的
03 线程
线程基础知识
线程的创建和start(参数传递)
using System;
using System.Net;
using System.Threading;
namespace threadtest
{
class Program
{
static void Main(string[] args)
{
//主线程执行main函数,除了主线程其他都是辅线程
//后台线程不会影响进程的终止,通过thread创建启动的进程是前台进程
//创建两个辅助线程,while循环输出当前时间,并且计数
//调试
//前台线程修改为后台线程,后台线程
Thread t1 = new Thread(F);
t1.IsBackground = true;
t1.Start();
//如果方法有参数,必须是object
//方法不能有返回值
Thread t2 = new Thread(GetHostName);
string ip = "127.0.0.1";//这个会得到本机的主机名
t2.Start(ip);//方法参数传到start
//方法有多个参数,把参数封装成一个类,传递类的实例,也可以用来实现多态
Thread t3 = new Thread(M);
MyClass m = new MyClass();
m.a = "1";m.b = "2";m.c = "3";
t3.Start(m);
}
public static void F()
{
int count = 0;
while (count<3)
{
count++;
//输出当前时间和次数
Console.WriteLine(DateTime.Now.ToLongTimeString()+"第"+count +"次");
Thread.Sleep(1000);//休眠1秒
}
}
public static void GetHostName(object ip)
{
try
{
Console.WriteLine(Dns.GetHostEntry(ip.ToString()).HostName);
}
catch (Exception)
{
Console.WriteLine("error");
}
}
public static void M(object obj)
{
MyClass m1 = obj as MyClass;
//MyClass m1 = (MyClass)obj;
Console.WriteLine(m1.a + m1.b + m1.c);
}
}
public class MyClass
{
public string a { get; set; }//必须设置属性,否则有保护机制无法访问字段
public string b { get; set; }
public string c { get; set; }
}
}
线程的两种终止方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace thread_test
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
Thread t1 = new Thread(F);
Thread t2 = new Thread(F);
volatile static bool isRun = true;
private void start_Click(object sender, RoutedEventArgs e)
{
t1.Start("a");
t2.Start("b");
}
public static void F(object str)
{
while (isRun)
{
Console.WriteLine(str.ToString());
Thread.Sleep(1000);
}
}
private void stop_Click(object sender, RoutedEventArgs e)
{
//两种终止线程 的方法
//isRun = false;
t1.Abort();
t2.Abort();
}
}
}
多任务网段扫描
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net;
using System.Diagnostics;
using System.Threading;
namespace testch01
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
lb.Visibility = Visibility.Hidden;
}
List<Thread> threads = new List<Thread>();
int num = 0, count = 0;
object obj = new object();
Stopwatch DuoxianchengWatch = new Stopwatch();
private void Button_Click(object sender, RoutedEventArgs e)
{
Button currentbutton = sender as Button;
tb.Text = "";
lb.Visibility = Visibility.Hidden;
string strqz = qz.Text;
string strqsz = qsz.Text;
string strzzz = zzz.Text;
string strip;
IPAddress ip1, ip2;
if(!(IPAddress.TryParse(strqz + strqsz,out ip1)&& IPAddress.TryParse(strqz + strzzz, out ip2)))
{
lb.Content = "IP地址有错,请更正 1812030065 李诗雨";
lb.Visibility = Visibility.Visible;
return;
}
int n = int.Parse(strzzz) - int.Parse(strqsz) + 1;
if (n <= 1)
{
lb.Content = "起始值终止值有误";
lb.Visibility = Visibility.Visible;
return;
}
for (int i = 0; i < n; i++)
{
strip = strqz + (int.Parse(strqsz) + i).ToString();
if (currentbutton.Content.ToString() == "单线程")
{
scan(strip);
}
else
{
DuoxianchengWatch.Start();
Thread t = new Thread(scan);
t.Start(strip);
threads.Add(t);
}
}
}
public void scan(object ip)
{
string hostname;
Stopwatch watch = new Stopwatch();
watch.Start();
IPHostEntry host = Dns.GetHostEntry(ip.ToString());
try
{
hostname = host.HostName.ToString();
}
catch (Exception)
{
hostname = "不能获取";
}
watch.Stop();
long ms = watch.ElapsedMilliseconds;
//委托给控件的创建线程(主线程)来完成
tb.Dispatcher.Invoke(() => tb.Text += "扫描地址: " + ip + " 扫描时间: " + ms + "毫秒" + " 主机DNS名称:" + hostname + "\n");
lock (obj)
{
num++;
}//保护数据在某个时刻内只有一个线程可以操作该数据,直至操作完毕才允许其他线程进行操作
count = threads.Count;
if (num == count)
{
DuoxianchengWatch.Stop();
tb.Dispatcher.Invoke(() => tb.Text += "1812030065 李诗雨 总时间:" + DuoxianchengWatch.ElapsedMilliseconds + "毫秒");
}
}
}
}
04 字符的编码和解码
using System;
using System.Text;
namespace test4
{
class Program
{
static void Main(string[] args)
{
all();
string str;
str= Console.ReadLine();
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
Encoding encodinggb2312 = Encoding.GetEncoding("gb2312");
Encoding encodingascll = Encoding.ASCII;
Encode(encodinggb2312, str);
Encode(encodingascll, str);
Console.WriteLine("1812030065 李诗雨");
}
/// <summary>
/// 编码和解码并输出结果
/// </summary>
/// <param name="e">编码方式</param>
/// <param name="str">要编码解码的字符串</param>
public static void Encode(Encoding e,string str)
{
//编码
byte[] bytes = e.GetBytes(str);
string encodeResult = BitConverter.ToString(bytes);
Console.WriteLine("编码:{0} ,编码结果{1}", e.EncodingName, encodeResult);
//解码
string s = e.GetString(bytes);
Console.WriteLine("解码结果:{0}", s);
Console.WriteLine();
}
/// <summary>
/// 显示本机的编码
/// </summary>
public static void all()
{
StringBuilder sb = new StringBuilder();
foreach (EncodingInfo ei in Encoding.GetEncodings())
{
Encoding en = ei.GetEncoding();
sb.AppendFormat("编码名称:{0},说明:{1}\n", ei.Name, en.EncodingName);
}
Console.WriteLine(sb.ToString());
}
}
}
05 文件流
c#项目中的不生成该文件
FileStream
using System;
using System.IO;
using System.Text;
namespace StreamTest
{
class File_stream
{
static void Main(string[] args)
{
//找文件
// 1.txt 要在该项目的exe文件的同级目录下.可以先设置断点,调试之后,打开项目所在文件夹
//在bin/debug 目录下创建(跟c++不一样,在右侧项目直接添加没用)
FileStream fs = new FileStream("1.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite);
//读取
byte[] buffer = new byte[1024];//设置缓冲区
//目标文件流
FileStream fsNew = new FileStream("2.txt", FileMode.Create, FileAccess.ReadWrite);
//buffer.length 是要读取的长度,num 返回实际读取的字节数
//0 这个是offset(偏移量) 开始读取的位置 一般设置为0, c#设置好的所以count 不用加上偏移量
// int num = fs.Read(byte[], offset, count);
while (fs.Read(buffer, 0, buffer.Length) > 0)
{
//解码(文件流读取的是字节序列,所以文件可以是文本,视频,音频等,这里是用文本演示)
//显示,注意保存的编码和解码要一致
Console.WriteLine(Encoding.UTF8.GetString(buffer));
//写入目标文件流
fsNew.Write(buffer, 0, buffer.Length);
}
//这里有个问题,就是最后一次判断出num=0的时候,
//按理说buffer里面已经没了数据,但我这个还保存上一次的,所以用do while 就有问题
//一定要关闭流,如果没有关闭,在此程序外就无法对文件进行操作
fs.Close();
fsNew.Close();
}
}
}
MemoryStream
注意 ms.position=0.
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace StreamTest
{
class Memory_stream
{
static void Main(String[] args)
{
//内存流 与文件流使用方法类似
string str = "abc.中国";
Console.WriteLine("写入的数据: {0}\n", str);
byte[] data = Encoding.UTF8.GetBytes(str);
//using 离开using代码块 流就会关闭
using (MemoryStream ms = new MemoryStream())
{
//利用write方法把字节数组的数据写到内存中
ms.Write(data, 0, data.Length);
//内存流随着读取 位置position自动移动,写完之后指针停留在末尾,直接开始读是读不到东西的
//内存流不能关闭,关闭再打开之后之前里面存的数据都没了
ms.Position = 0;
//利用read 方法把内存流中的数据读取到字节数组中
byte[] bytes = new byte[data.Length];
int n = ms.Read(bytes, 0, bytes.Length);
//显示读取的数据
string s = Encoding.UTF8.GetString(bytes);
Console.WriteLine("读取的数据: {0}", s);
}
}
}
}
Stream Reader Writer
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace StreamTest
{
class Stream_Reader_Writer
{
static void Main(String[] args)
{
//stream reader writer 只适用于文本(txt),实际是一个封装的简化文本传输的类
FileStream fs = new FileStream("1.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite);
FileStream fsNew = new FileStream("2.txt", FileMode.Create, FileAccess.ReadWrite);
StreamReader sr = new StreamReader(fs,Encoding.Unicode);//默认是UTF8
StreamWriter sw = new StreamWriter(fsNew);
//while (sr.ReadLine()!=null)
//{
// sw.WriteLine(sr.ReadLine());
//} 在判断条件里面已经调用了一次readline (每次都会少一行)
string strLine;
while ((strLine=sr.ReadLine())!=null)
{
sw.WriteLine(strLine);
}
//一定要关闭流,如果没有关闭,在此程序外就无法对文件进行操作
fs.Close();
sr.Close();
sw.Close();
//如果先执行 fsNew.Close( );再执行 sw.Close( );将引发异常。因为在StreamWriter的Close函数调用过程中,将调用Flush函数,而此时fs已经被关闭,Flush将产生异常。
}
}
}
StreamWriter、StreamReader与FileStream的关闭总结
binary reader writer
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace StreamTest
{
class Binary_Stream
{
static void Main(String[] args)
{
if (File.Exists("3.txt"))
{
File.Delete("3.txt");
}
FileStream fs = new FileStream("3.txt", FileMode.CreateNew, FileAccess.ReadWrite);
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(0);//4个字节
float ft = 1;
bw.Write(ft);
bw.Write("ssss");
fs.Position = 0;
//bw.close()执行,fs流就会关闭,fs 就是不可读的状态了
//对该流未处理完不要关
StreamReader sr = new StreamReader(fs);
BinaryReader br = new BinaryReader(fs);
int x1 = br.ReadInt32();
float x2 = br.ReadSingle();
string s = br.ReadString();
//注意存进去的数据是按照字节保存,取出来的时候要按照存入数据类型的顺序
Console.WriteLine("{0}, {1}, {2}", x1, x2, s);
br.Close();
fs.Close();
}
}
}
06 数据加密和解密
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Threading.Tasks;
using System.IO;
namespace testCh04
{
class Program
{
/// <summary>使用AES算法加密</summary>
public static byte[] Encryptstring(string strpath,byte[] key,byte[] iv)
{
byte[] encrpted;
using (Aes aesAlg = Aes.Create())
{
//创建加密器
ICryptoTransform encryptor = aesAlg.CreateEncryptor(key, iv);
//创建文件流和加密流
FileStream fs = new FileStream(strpath, FileMode.Open, FileAccess.ReadWrite);
CryptoStream cs = new CryptoStream(fs, encryptor, CryptoStreamMode.Read);
using (BinaryReader br = new BinaryReader(cs))
{
encrpted = br.ReadBytes(10240);
}
fs.Close();
cs.Close();
}
return encrpted;
}
/// <summary>使用AES算法解密</summary>
public static byte[] DescrptString(string strpath,byte[] key, byte[] iv)
{
byte[] decrypted;
using (Aes aesAlg = Aes.Create())
{
//创建解密器
ICryptoTransform decryptor = aesAlg.CreateDecryptor(key, iv);
//创建文件流和解密流
FileStream fs = new FileStream(strpath, FileMode.Open, FileAccess.ReadWrite);
CryptoStream cs = new CryptoStream(
fs,
decryptor,
CryptoStreamMode.Read);
try
{
using (BinaryReader br = new BinaryReader(cs))
{
decrypted = br.ReadBytes(10240);
}
}
catch (Exception)
{
Console.WriteLine("解密密码错误");
decrypted = null;
}
cs.Close();
fs.Close();
}
return decrypted;
}
/// <summary>根据提供的密码生成Key和IV</summary>
public static void GenKeyIV(string password, out byte[] key, out byte[] iv)
{
using (Aes aesAlg = Aes.Create())
{
key = new byte[aesAlg.Key.Length];
byte[] pwdBytes = Encoding.UTF8.GetBytes(password);
for (int i = 0; i < pwdBytes.Length; i++)
{
key[i] = pwdBytes[i];
}
iv = new byte[aesAlg.IV.Length];
for (int i = 0; i < pwdBytes.Length; i++)
{
iv[i] = pwdBytes[i];
}
}
}
static void Main(string[] args)
{
//读取明文文件
FileStream fsMingWen = new FileStream("明文.txt", FileMode.Open, FileAccess.ReadWrite);
StreamReader srMingWen = new StreamReader(fsMingWen);
Console.WriteLine(srMingWen.ReadToEnd());
fsMingWen.Close();
srMingWen.Close();
//加密
string password;
Console.WriteLine("请输入密码加密");
password = Console.ReadLine();
byte[] key;
byte[] iv;
//根据提供的密码生成Key和IV
GenKeyIV(password, out key, out iv);
//把密文数据写入密文文件
if (File.Exists("密文.txt"))
{
File.Delete("密文.txt");
}
FileStream fsMiWen = new FileStream("密文.txt", FileMode.CreateNew, FileAccess.ReadWrite);
byte[] buffer;
buffer = Encryptstring("明文.txt", key, iv);
fsMiWen.Write(buffer, 0, buffer.Length);
fsMiWen.Close();
Console.WriteLine("加密完成");
//解密
Console.WriteLine("请输入密码解密");
password = Console.ReadLine();
//根据提供的密码生成Key和IV
GenKeyIV(password, out key, out iv);
//把解密数据写入解密文文件
if (File.Exists("解密文.txt"))
{
File.Delete("解密文.txt");
}
FileStream fsJieMiWen = new FileStream("解密文.txt", FileMode.CreateNew, FileAccess.ReadWrite);
buffer = DescrptString("密文.txt", key, iv);
if (buffer == null)
{
Console.ReadKey();
return;
}
fsJieMiWen.Write(buffer, 0, buffer.Length);
//读取 解密文
fsJieMiWen.Position = 0;//刚往文件写入,指针停在最后了,读取是从指针开始
StreamReader srJieMi = new StreamReader(fsJieMiWen);
Console.WriteLine("解密完成,解密文为:");
string s = srJieMi.ReadToEnd();
Console.WriteLine(s);
fsJieMiWen.Close();
srJieMi.Close();
Console.ReadKey();
}
}
}
07 异步编程
委托,lambda,Action和Func委托
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
//委托 定义委托和定义方法相似。委托能够代表什么样的方法由它的返回值类型和参数列表决定
public delegate int MyDelegate(int x);//在class内外都可以声明
public static int F1(int x)
{
// return x++; 先返回x后x++
Console.Write("F1 ");
return ++x;
}
public static int F2(int x)
{
Console.Write("F2 ");
return --x;
}
public static int F3(int x)
{
Console.Write("F3 ");
return x - 2;
}
public static void F4()
{
Console.WriteLine("F4 ");
}
static void Main(string[] args)
{
int x = 10;
//委托
MyDelegate d1 = new MyDelegate(F1);//声明委托变量并实例化
Console.WriteLine(d1(x));
d1 = F2;//委托可以更换绑定的方法,委托也可以直接赋值为方法
Console.WriteLine(d1(x));
d1 += F1;//可以添加绑定方法,执行完F2接着执行 F1
Console.WriteLine(d1(x));
//Action 委托
//Action<T1,T2> 等价于Public delegate void Action<in T1,in T2>(T1 a,T2 b)
//T1~T16表示输入参数的类型,参数可以是0~16个
//Func 委托
//Func<T1,T2,TResult> 等价于Public delegate void Func<in T1,in T2,out TResult>(T1 a,T2 b)
//T1~T16表示输入参数的类型,参数可以是0~16个,写在最后的一个是返回值类型
//Lambda 表达式
//创建 Lambda 表达式的简单语法形式:输入参数列表 => {表达式或语句块};
//使用匿名方法实现
Func<int, int> func1 = (int x) => x - 2;//lambda表达式简写函数F3,语句块只有一行可直接写
Func<int, string, string> func2 = (int x, string s) =>
{
string str;
if (s.Length > x)
return str = "s.Length>x";
else return str = "s.Length<=x";
};
Func<int, int, bool> func3 = (x, y) => x == y;//Lambda 表达式的参数可以不写类型
Func<int,int> func4 = x => x * x;//Lambda 表达式的参数只有一个时可不写括号
Console.WriteLine(func1(x));
Console.WriteLine(func2(x,"1234"));
Console.WriteLine(func3(x,10));
Console.WriteLine(func4(x));
Action action1 = () => F4();//无参情况
action1();
Action<int, int> action2 = (x, y) => Console.WriteLine(x + y);
action2(x, x);
//lambda和LINQ
List<int> numberList = new List<int> { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
//两种方法返回小于4的元素
var q1 = numberList.Where(i => i < 4);
var q2 = from i in numberList
where i < 4
select i;
}
}
}
基于任务的异步模式
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Class1
{
//创建异步方法
//根线程比的优势:await ,如果用线程,想拿到线程方法的返回值,需要访问
//共同的变量,还要判断线程执行完毕,很麻烦
// 普通方法:如果方法没有返回值,则用async和Task共同签名。
// 如果方法有返回值,则用async和Task<T> 共同签名
public async Task Method1Async()
{
//await运算符表示等待异步执行的结果。实质上对方法的返回值进行操作。
//使用await异步等待任务完成时,不会执行其后面的代码,但也不会影响用户对UI的操作。
await Task.Delay(100);
}
public static async Task<int> Method2Async()
{
await Task.Delay(100);//延迟模拟耗时操作
return 10;
}
//异步方法的命名约定
//方法后面以“Async”做为后缀 。
public static void Method3()
{
System.Threading.Thread.Sleep(1000);
}
public async Task Method4Async()
{
Task task1 = Task.Run(() => Method3());
//。。。。不一定调用完task1就立马拿结果中间可有其他代码
await task1;//await 必须在异步方法内否则找不到引用
}
static void Main(string[] args)
{
//任务(Task) 表示一个异步操作。
// 1.Task类:表示一个没有返回值的异步操作。自动创建一个辅助线程
Task t = Task.Run(() =>
{ Console.WriteLine("this is a task"); });
//作用类似于
//Thread a=new Thread(方法名);
// a.Start();
// 2.Task<TResult> 类:表示一个可以返回值的异步操作。
var t2 = Task<int>.Run(() =>
{
int num = 5; num = DateTime.Now.Year + 5;
return num;
});//t2其实也是一个task
//task.Dleay 和 sleep 的区别是 仅仅调用task.Dleay没有任何作用是异步延迟,这个会创建一个辅助线程去延迟,
//结合await关键字,可实现同步延迟
}
}
}
多任务网段扫描(Task)
使用await的优势是代码执行顺序和同步一样但是因为创建辅助线程执行耗时操作,界面不会卡顿。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net;
using System.Diagnostics;
using System.Threading;
namespace testch01
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
lb.Visibility = Visibility.Hidden;
}
public static List<Thread> threads = new List<Thread>();
public static int num, count,sum ;
public static object obj = new object();
public static Stopwatch DuoxianchengWatch = new Stopwatch();
public static Stopwatch DuorenwuWatch = new Stopwatch();
private async void Button_Click(object sender, RoutedEventArgs e)
{
Button currentbutton = sender as Button;
tb.Text = "";
lb.Visibility = Visibility.Hidden;
string strqz = qz.Text;string strqsz = qsz.Text;string strzzz = zzz.Text;
string strip;
IPAddress ip1, ip2;
if(!(IPAddress.TryParse(strqz + strqsz,out ip1)&& IPAddress.TryParse(strqz + strzzz, out ip2)))
{
lb.Content = "IP地址有错,请更正 1812030065 李诗雨";
lb.Visibility = Visibility.Visible;
return;
}
int n = int.Parse(strzzz) - int.Parse(strqsz) + 1;
if (n <= 1)
{
lb.Content = "起始值终止值有误";
lb.Visibility = Visibility.Visible;
return;
}
DuoxianchengWatch.Start();
DuorenwuWatch.Start();
sum = n;
for (int i = 0; i < n; i++)
{
strip = strqz + (int.Parse(strqsz) + i).ToString();
if (currentbutton.Content.ToString() == "单线程")
{
scan(strip);
}
else if(currentbutton.Content.ToString() == "多线程")
{
Thread t = new Thread(scan);
t.Start(strip);
threads.Add(t);
}
else
{
scan2Asnyc(strip);
}
}
foreach (Task<string> item in tasks)
{
await item;
}
}
List<Task<string>> tasks = new List<Task<string>>();
public void scan(object ip)
{
string hostname;
Stopwatch watch = new Stopwatch();
watch.Start();//多线程中的一个线程解析所用时间
//解析主机名
try
{
IPHostEntry host = Dns.GetHostEntry(ip.ToString());
hostname = host.HostName.ToString();
}
catch (Exception)
{
hostname = "不能获取";
}
watch.Stop();
long ms = watch.ElapsedMilliseconds;
//委托给控件的创建线程(主线程)来完成输出(涉及到tb)
tb.Dispatcher.Invoke(() => tb.Text += "扫描地址: " + ip + " 扫描时间: " + ms + "毫秒" + " 主机DNS名称:" + hostname + "\n");
//输出总时间
lock (obj)
{
num++;
}//保证num++是在一个线程内完成
count = threads.Count;
if (num == count)
{
DuoxianchengWatch.Stop();
tb.Dispatcher.Invoke(() => tb.Text += "1812030065 李诗雨 总时间:" + DuoxianchengWatch.ElapsedMilliseconds + "毫秒");
}
}
public async Task scan2Asnyc(string ip)
{
string hostname;
Stopwatch watch = new Stopwatch();
watch.Start();//解析一个ip的时间
//解析主机名
Task<string> task = Task<string>.Run(()=> scan2(ip));
tasks.Add(task);
watch.Stop();
long ms = watch.ElapsedMilliseconds;
tb.Text += "扫描地址: " + ip + " 扫描时间: " + ms + "毫秒" + " 主机DNS名称:" + hostname + "\n";
num++;
if (num == sum)
{
tb.Text += "1812030065 李诗雨 总时间:" + DuorenwuWatch.ElapsedMilliseconds + "毫秒";
}
}
public string scan2(string ip)
{
string hostname;
try
{
IPHostEntry host = Dns.GetHostEntry(ip);
hostname = host.HostName.ToString();
}
catch (Exception)
{
hostname = "不能获取";
}
return hostname;
//Console.WriteLine(Thread.CurrentThread.ManagedThreadId);输出当前线程id
//await 只用在异步方法中,异步方法中只有await后的语句是创建一个辅助线程,其他语句都是主线程
}
}
}
await 只能用于异步方法中,异步方法中只有await后的语句是创建一个辅助线程,其他语句都是主线程执行。如果事件处理程序用到await,要用asnyc void 签名。
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);输出当前线程id可以检查当前线程。
下面的代码实际上还是顺序执行的,即一个个扫描。可以优化。
public async Task scan2Asnyc(string ip)
{
string hostname;
Stopwatch watch = new Stopwatch();
watch.Start();//解析一个ip的时间
//解析主机名
Task<string> task = Task<string>.Run(()=> scan2(ip));
hostname = await task;
watch.Stop();
long ms = watch.ElapsedMilliseconds;
tb.Text += "扫描地址: " + ip + " 扫描时间: " + ms + "毫秒" + " 主机DNS名称:" + hostname + "\n";
num++;
if (num == sum)
{
tb.Text += "1812030065 李诗雨 总时间:" + DuorenwuWatch.ElapsedMilliseconds + "毫秒";
}
}
优化:用泛型列表
List<Task<string>> tasks = new List<Task<string>>();
```csharp
//解析主机名
Task<string> task = Task<string>.Run(()=> scan2(ip));
tasks.Add(task);
foreach (Task<string> item in tasks)
{
await item;
}