目录
线程
在运用多线程技术之前,先得理解什么是线程。
那什么是线程呢?说到线程就不得不先说说进程。通俗的来讲,进程就是个应程序开始运行,那么这个应用程序就会存在一个属于这个应用程序的进程。
那么线程就是进程中的基本执行单元,每个进程中都至少存在着一个线程,这个线程是根据进程创建而创建的,所以这个线程我们称之为主线程。
那么多线程就是包含有除了主线程之外的其他线程。
如果一个线程可以执一个任务,那么多线程就是可以同时执行多个任务。
线程的基本用法:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace 线程
{
public partial class Form1 : Form
{
private List<Thread> ThreadPool = new List<Thread>();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Thread thread = new Thread(TestThread);
ThreadPool.Add(thread);
thread.Start();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if(ThreadPool.Count > 0)
{
foreach (Thread thread in ThreadPool)
{
if (thread.IsAlive)//当前线程是否终止
{
thread.Abort();//终止线程
}
}
}
}
private void TestThread()
{
for (int i = 0; i <= 10; i++)
{
Console.WriteLine("输出:" + i);
Thread.Sleep(500);
}
}
private void Button_Test_Click(object sender, EventArgs e)
{
if (ThreadPool.Count > 0)
{
foreach (Thread thread in ThreadPool)
{
Console.WriteLine("当前线程是否终止:" + thread.IsAlive);
}
}
}
}
}
MD5加密
/// <summary>
/// 计算md5
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
private string CalcMD5(string str)
{
byte[] buffer = Encoding.UTF8.GetBytes(str);
using (MD5 md5 = MD5.Create())
{
byte[] md5Bytes = md5.ComputeHash(buffer);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < md5Bytes.Length; i++)
{
sb.Append(md5Bytes[i].ToString("x2"));//X2时,生成字母大写MD5
}
return sb.ToString();
}
}
计算两个时间间隔
代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Utils
{
public class TimeInterval
{
/// <summary>
/// 计算两个时间间隔的时长
/// </summary>
/// <param name="TimeType">返回的时间类型</param>
/// <param name="StartTime">开始时间</param>
/// <param name="EndTime">结束时间</param>
/// <returns>返回间隔时间,间隔的时间类型根据参数 TimeType 区分</returns>
public static double GetSpanTime(TimeType TimeType, DateTime StartTime, DateTime EndTime)
{
TimeSpan ts1 = new TimeSpan(StartTime.Ticks);
TimeSpan ts2 = new TimeSpan(EndTime.Ticks);
TimeSpan ts = ts1.Subtract(ts2).Duration();
//TimeSpan ts = EndTime - StartTime;
double result = 0f;
switch (TimeType)
{
case TimeType.MilliSecond:
result = ts.TotalMilliseconds;
break;
case TimeType.Seconds:
result = ts.TotalSeconds;
break;
case TimeType.Minutes:
result = ts.TotalMinutes;
break;
case TimeType.Hours:
result = ts.TotalHours;
break;
case TimeType.Days:
result = ts.TotalDays;
break;
}
return result;
}
}
/// <summary>
/// 时间类型
/// </summary>
public enum TimeType
{
/// <summary>
/// 毫秒
/// </summary>
MilliSecond,
/// <summary>
/// 秒
/// </summary>
Seconds,
/// <summary>
/// 分钟
/// </summary>
Minutes,
/// <summary>
/// 小时
/// </summary>
Hours,
/// <summary>
/// 天
/// </summary>
Days,
/// <summary>
/// 月
/// </summary>
Months
}
}
调用:
class Program
{
static void Main(string[] args)
{
DateTime dateTime1 = DateTime.Now;
Thread.Sleep(3000);
DateTime dateTime2 = DateTime.Now;
double timeDifference = TimeInterval.GetSpanTime(timeType, dateTime1, dateTime2);
Console.WriteLine(string.Format("{0} {1}", timeDifference, timeType.ToString()));
Console.ReadKey();
}
}
输出:
3 Seconds
数组等比例缩放
新建一个C#控制台项目,要新建.NetFramework类型的,不然下面代码中的某些API无法使用。
代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Test1
{
class Program
{
static void Main(string[] args)
{
List<double> resultList = ScaleConversion(new List<double>() { 230, 2453, 4353, 65 }, 10);
string value = string.Empty;
for (int i = 0; i < resultList.Count; i++)
{
value += string.Format("{0},", resultList[i]);
}
Console.WriteLine(value);
Console.ReadKey();
}
/// <summary>
/// 将数组等比例缩放
/// </summary>
/// <param name="valueList">数组</param>
/// <param name="maxScale">缩放的最大值,最小值默认为0</param>
/// <returns>缩放后的数组</returns>
public static List<double> ScaleConversion(List<double> valueList, int maxScale)
{
if (valueList == null || valueList.Count == 0)
{
Console.WriteLine("valueList 不能为空");
return null;
}
if (maxScale < 10)
{
Console.WriteLine("等比例的最大值不能小于10");
return null;
}
double max = valueList.Max();
double factor = Math.Round(max / maxScale, 2);//系数
List<double> result = new List<double>();
for (int i = 0; i < valueList.Count; i++)
{
result.Add(Math.Round(valueList[i] / factor, 2));
}
if (result.Count > 0)
return result;
return null;
}
}
}
运行后,结果是:0.53,5.64,10,0.15,
这里是将10做为缩放比例中的最大值,有兴趣的读者可以自己算一下是否正确。
时间加减
代码:
using System;
namespace Util
{
public class TimeCompute
{
/// <summary>
/// 时间间隔
/// </summary>
/// <param name="DateTime1">时间1</param>
/// <param name="DateTime2">时间2</param>
/// <returns>同一天的相隔的分钟的整数部分</returns>
public static int DateDiff(DateTime DateTime1, DateTime DateTime2)
{
TimeSpan ts1 = new TimeSpan(DateTime1.Ticks);
TimeSpan ts2 = new TimeSpan(DateTime2.Ticks);
TimeSpan ts = ts1.Subtract(ts2).Duration();
return Convert.ToInt32(ts.TotalMinutes);
}
/// <summary>
/// 时间相加
/// </summary>
/// <param name="DateTime1">时间1</param>
/// <param name="DateTime2">时间2</param>
/// <returns>时间和</returns>
public static DateTime DateSum(DateTime DateTime1, DateTime DateTime2)
{
DateTime1 = DateTime1.AddHours(DateTime2.Hour);
DateTime1 = DateTime1.AddMinutes(DateTime2.Minute);
DateTime1 = DateTime1.AddSeconds(DateTime2.Second);
return DateTime1;
}
/// <summary>
/// 根据秒数得到 DateTime
/// </summary>
/// <param name="seconds">秒数</param>
/// <returns>以1970-01-01为日期的时间</returns>
public static DateTime GetDateTimeBySeconds(double seconds)
{
return DateTime.Parse(DateTime.Now.ToString("1970-01-01 00:00:00")).AddSeconds(seconds);
}
/// <summary>
/// 根据 DateTime 得到秒数
/// </summary>
/// <param name="timer">时间</param>
/// <returns>秒数</returns>
public static double GetDateTimeBySeconds(DateTime dateTime)
{
return (Convert.ToInt32(dateTime.Hour) * 3600) + (Convert.ToInt32(dateTime.Minute) * 60) + Convert.ToInt32(dateTime.Second);
}
}
}
将字符串转换为时间
这里也可以使用 DateTime.Parse 进行转换,如果时间字符串写的不齐,只有时间,没有日期,就会以当前的日期和字符串中的时间进行组合
DateTime dt = Convert.ToDateTime("1:00:00");
两个时间相减
DateTime t1 = DateTime.Parse("2007-01-01");
DateTime t2 = DateTime.Parse("2006-01-01");
TimeSpan t3 = t1 - t2;
字符串转换DateTime类型
代码
//下面这两种字符串写法都可以
string timer = "2022-02-02 18:15:58";
string timer = "2022/2/18 18:18:26";
DateTime dateTime = Convert.ToDateTime(timer);
Console.WriteLine(dateTime);
Net5添加管理员权限 以管理员身份运行
在 项目 上 添加新项 选择“应用程序清单文件” 然后单击 添加 按钮
添加后,默认打开app.manifest文件,将:
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
修改为:
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
重新生成项目,再次打开程序时就会提示 需要以管理员权限运行。
Task执行任务,等待任务完成
代码:
//任务
Func<int> Funcs = () =>
{
Console.WriteLine("任务开始");
return 1 + 1;
};
//执行任务
Task<int> printRes = Task.Run(Funcs);
//等待任务完成
printRes.GetAwaiter().OnCompleted(() =>
{
Console.WriteLine("异步执行结果:" + printRes.Result);
});
运行:
任务开始
异步执行结果:2
用“\”分割字符
string Chars = @"\";
string Text = @"ddsdd\dddds";
string[] Arr = Text.Split(new[] { Chars },StringSplitOptions.None);
//结果:Arr[0] = "ddsdd, Arr[1] = dddds
实现模拟键盘按键
1.发送字符串,这里的字符串可以为任意字符
private void button1_Click(object sender,EventArgs e)
{
textBox1.Focus();
SendKeys.Send("{A}");
}
2.模拟组合键:CTRL + A
private void button1_Click(object sender,EventArgs e)
{
webBrowser1.Focus();
SendKeys.Send("^{A}");
}
3.SendKeys.Send 异步模拟按键(不阻塞UI)
按键参考:虚拟键码 (Winuser.h) - Win32 apps | Microsoft Docs
[DllImport("user32.dll", EntryPoint = "keybd_event", SetLastError = true)]
//bvk 按键的虚拟键值,如回车键为 vk_return, tab 键为 vk_tab(其他具体的参见附录)
//bScan 扫描码,一般不用设置,用 0 代替就行;
//dwFlags 选项标志,如果为 keydown 则置 0 即可,如果为 keyup 则设成 "KEYEVENTF_KEYUP";
//dwExtraInfo 一般也是置 0 即可。
public static extern void keybd_event(Keys bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
private void button1_Click(object sender,EventArgs e)
{
textBox1.Focus();
keybd_event(Keys.A, 0, 0, 0);
}
4.模拟组合键:CTRL + A
public const int KEYEVENTF_KEYUP = 2;
private void button1_Click(object sender,EventArgs e)
{
webBrowser1.Focus();
keybd_event(Keys.ControlKey,0,0,0);
keybd_event(Keys.A,0,0,0);
keybd_event(Keys.ControlKey,KEYEVENTF_KEYUP,0,0);
}
5.上面两种方式都是全局范围呢,现在介绍如何对单个窗口进行模拟按键
下面代码没测试过,不知道有用没有
[DllImport("user32.dll",EntryPoint = "PostMessageA",SetLastError = true)]
public static extern int PostMessage(IntPtr hWnd,int Msg,Keys wParam,int lParam);
public const int WM_CHAR = 256;
private void button1_Click(object sender,EventArgs e)
{
textBox1.Focus();
PostMessage(textBox1.Handle,256,Keys.A,2);
}
public const int WM_KEYDOWN = 256;
public const int WM_KEYUP = 257;
private void button1_Click(object sender,0)
{
PostMessage(webBrowser1.Handle,WM_KEYDOWN,0);
}
代码运行耗时
这个功能在代码实现上比较简单,几行代码就可以做到
声明计时器
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
暂停计时器,输出时间
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed.Minutes + "分" + stopwatch.Elapsed.Seconds + "秒");
如果需要分段多次计时,那么就需要将计时器清空
stopwatch.Stop();
stopwatch.Reset();
stopwatch.Start();
通过反射获取和设置指定的属性
public class Program
{
//定义类
public class MyClass
{
public int Property1 { get; set; }
}
static void Main()
{
MyClass tmp_Class = new MyClass();
tmp_Class.Property1 = 2;
//获取类型
Type type = tmp_Class.GetType();
//获取指定名称的属性
System.Reflection.PropertyInfo propertyInfo = type.GetProperty("Property1");
//获取属性值
int value_Old = (int)propertyInfo.GetValue(tmp_Class, null);
Console.WriteLine(value_Old);
//给对应属性赋值
propertyInfo.SetValue(tmp_Class, 5, null);
int value_New = (int)propertyInfo.GetValue(tmp_Class, null);
Console.WriteLine(value_New);
Console.ReadLine();
}
}
end