实现通用打印泛型类
在我们日常进行程序的编写与测试时,时常有需要将数组,栈,队列等的数据结构中存储的内容输出出来的需求,为了我们日常使用的方便,我们创建一个工具类的静态方法,解决这个问题。
为了实现通用这个属性,我们需要对这些数据结构进行分析,经过分析后,发现它们都继承了IEnumerable这个类,所以我们在定义参数类型时,需要限制传入的参数是IEnumerable这个类,又因为这些数据结构中存储的类型未知,所以它们的泛型约束为T。接着将传入的的数据结构按照for或者foreach进行打印即可。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DJConsoleProject
{
//自定义工具类
//泛型类
internal class DJTools
{
//通用的打印
static public void println<T>(IEnumerable<T> collection)
{
foreach (T item in collection)
{
Console.Write(item + " ");
}
Console.WriteLine();
}
}
}
计算遍历目录的耗时
计算遍历目录的耗时,首先要将遍历目录的方法写出来,很明显的需要借用递归进行遍历,以下是遍历目录的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace DJConsoleProject;
using System.Collections.Generic;
internal class DirectoryTraversal
{
private int file_num=0;
private Dictionary<string, int> ext_data = new Dictionary<string, int>();
public void TraverseDirectory(string path)
{
string[] files = Directory.GetFiles(path);
string[] directories = Directory.GetDirectories(path);
// 遍历文件
foreach (string file in files)
{
FileInfo fileInfo = new FileInfo(file);
//Console.WriteLine("文件名为"+fileInfo.Name);
file_num += 1;
if(ext_data.ContainsKey(fileInfo.Extension))
{
ext_data[fileInfo.Extension]++;
}
else
{
ext_data.Add(fileInfo.Extension, 1);
}
}
// 遍历目录,并递归调用本方法
foreach (string directory in directories)
{
//Console.WriteLine("目录为:"+directory);
TraverseDirectory(directory);
}
}
public void LookData()
{
Console.WriteLine("文件数量为:"+file_num);
foreach (var item in ext_data)
{
Console.WriteLine(item.Key + ":" + item.Value);
}
}
}
上述代码可以遍历出所给的目录下的所有文件,然后在启动类中调用该方法,在运行方法前,创建Stopwatch类的实例对象,该类是专门用来测算程序运行的时间的,性能比Timespan类好且准确,推荐使用。
using DJConsoleProject;
using System.Diagnostics;
Stopwatch sw = Stopwatch.StartNew();
sw.Start();
DirectoryTraversal directoryTraversal = new DirectoryTraversal();
directoryTraversal.TraverseDirectory("C:\\Users\\86134\\Desktop\\软件工程作业");
sw.Stop();
Console.WriteLine("共耗费{0}ms",sw.ElapsedMilliseconds);
在启动类中调用,并计算耗费的时间。以下时我的运行结果。
运算符的类型
算术运算符
+
加法-
减法*
乘法/
除法%
取模(求余数)
赋值运算符
=
简单赋值+=
加法赋值-=
减法赋值*=
乘法赋值/=
除法赋值%=
取模赋值&=
位与赋值|=
位或赋值^=
异或赋值<<=
左移赋值>>=
右移赋值
比较运算符(关系运算符)
<
小于>
大于<=
小于等于>=
大于等于==
相等!=
不相等
逻辑运算符
&&
逻辑与||
逻辑或!
逻辑非
位运算符
&
位与|
位或^
异或~
按位取反<<
左移>>
右移
条件运算符(三元运算符)
?:
格式:condition ? value_if_true : value_if_false
成员访问运算符
.
成员访问->
结构体指针成员访问
特殊运算符
?.
空条件运算符(空安全调用)??
空合并运算符??=
空合并赋值运算符
三目表达式
在C#中,三目表达式(也称作条件运算符)是一种简化版的if-else
语句,它可以让你在一行代码内基于某个条件来选择两个可能的值之一。三目表达式的语法如下:
条件表达式 ? 值如果真 : 值如果假;
这里的条件表达式
必须产生一个布尔值(true
或 false
)。如果条件表达式的结果为true
,那么整个表达式的结果就是值如果真
,否则结果就是值如果假
。例子:
int x = 10;
int y = 20;
int max = x > y ? x : y;
Console.WriteLine(max); // 输出 20
运算符的优先级
在C#中,运算符的优先级决定了表达式中各个部分的计算顺序。当一个表达式包含多个不同类型的运算符时,高优先级的运算符会先于低优先级的运算符进行计算。优先级口诀:有括号先括号,后乘除再加减,然后位移再关系,逻辑完后再条件。如果分不清优先级,比较推荐多使用括号,可以更好的看出优先级。下表按最高优先级到最低优先级的顺序列出 C# 运算符。 每行中运算符的优先级相同。
运算符 | 类别或名称 |
---|---|
x.y、f(x)、a[i]、x?.y、x?[y]、x++、x--、x!、new、typeof、checked、unchecked、default、nameof、delegate、sizeof、stackalloc、x->y | 主要 |
+x、-x、x、~x、++x、--x、^x、(T)x、await、&&x、*x、true 和 false | 一元 |
x..y | 范围 |
switch、with | switch 和 with 表达式 |
x * y、x / y、x % y | 乘法 |
x + y、x – y | 加法 |
x << y、x >> y | Shift |
x < y、x > y、x <= y、x >= y、is、as | 关系和类型测试 |
x == y、x != y | 相等 |
x & y | 布尔逻辑 AND 或按位逻辑 AND |
x ^ y | 布尔逻辑 XOR 或按位逻辑 XOR |
x | y | 布尔逻辑 OR 或按位逻辑 OR |
x && y | 条件“与” |
x || y | 条件“或” |
x ?? y | Null 合并运算符 |
c ? t : f | 条件运算符 |
x = y、x += y、x -= y、x *= y、x /= y、x %= y、x &= y、x |= y、x ^= y、x <<= y、x >>= y、x ??= y、=> | 赋值和 lambda 声明 |
break,continue,return的区别
在编程中,`break`、`continue`和`return`是控制流程的关键字,它们分别用于不同的目的。下面是这三种关键字的主要区别和用法:
1. **break**
- 用途:`break`关键字用于完全退出循环(`for`、`while`、`do-while`)或`switch`语句。
- 效果:当`break`在一个循环中被触发时,它会立即停止当前循环的执行,跳过循环剩余的部分,然后继续执行紧跟在循环之后的第一条语句。
for (int i = 0; i < 10; i++)
{
if (i == 5)
break;
Console.WriteLine(i);
}
执行结果:
2. **continue**
- 用途:`continue`关键字用于跳过循环体中剩余的代码,并直接进行到下一次循环的开始。
- 效果:当`continue`在一个循环中被触发时,它会立即跳过当前迭代中剩余的所有代码,然后开始下一次循环的条件检查。
for (int i = 0; i < 10; i++)
{
if (i % 2 == 0)
continue;
Console.WriteLine(i);
}
执行结果:
3. **return**
- 用途:`return`关键字用于从一个函数或方法中返回,并可选地带回一个值。
- 效果:`return`会立即结束当前函数或方法的执行,跳过所有剩余的代码,然后将控制权返回给调用者。如果函数有返回类型,`return`可以跟一个表达式一起使用,作为返回值。
int test()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
if (i == 5)
return 0;
}
Console.WriteLine("**********");
return 1;
}
test();
运行结果:可以看出return后面的代码直接就没有运行。
在实际应用中,`break`和`continue`通常用于循环内部,以根据某些条件提前结束循环或跳过某次迭代。`return`则用于函数的任何地方,但通常位于函数的末尾,除非你使用它来提前退出函数。
冒泡排序
冒泡排序的本质是双重for循环,它是比较慢的算法,因为它遍历一次数组只能确定一个元素的位置,外面的i控制需要遍历几次,才能排序成功,比如如果arr有7个元素,那么需要遍历6次,才能完全排序成功。里面的j控制每次遍历需要比较的次数,因为每次i遍历一次就确定了一个元素的位置,下一次的遍历就可以少比较一个元素,所以j=arr.Length-i-1。-1是因为数组是从0开始的,这就是冒泡排序的过程。
using DJConsoleProject;
int[] arr = {1,37,24,3,13,78,12,83,26,4};
for (int i = 0; i < arr.Length-1; i++)
{
for (int j = 0; j <arr.Length-i-1 ; j++)
{
int temp = 0;
if (arr[j] > arr[j+1])
{
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
DJTools.println(arr);
程序运行的结果:
打印九九乘法表
打印九九乘法表是我们编程的一道基础题,使用双重for循环即可轻松实现。主要注意循环要从1开始,因为乘法表就是从一开始的。
for(int i=1;i<10;i++)
{
for(int j=1;j<i+1;j++)
{
Console.Write("{0}*{1}={2} ", j, i, i * j);
}
Console.WriteLine();
}
程序运行结果:
文件找不到抛出异常
在我们的日常编程过程中,我们希望实现一个如果文件不存在,则抛出异常提示。我们可以通过throw抛出异常。该checkfile方法可以判断传入的路径是否存在,如果不存在就抛出文件不存在的警告。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DJConsoleProject
{
public class checkfile
{
static public void FileCheck(string path)
{
if (!File.Exists(path))
{
throw new FileNotFoundException(string.Format("文件{0}未找到。",path));
}
}
}
}
在启动类中调用,我传入的是我电脑中并不存在的路径。
using DJConsoleProject;
try
{
string path = "C:\\Users\\86134\\Desktop\\软件工程作";
checkfile.FileCheck(path);
}
catch (FileNotFoundException ex)
{
Console.WriteLine(ex.Message);
}
以下是运行结果,在try的代码段中成功的抛出了FileNotFoundException类型的错误,并被成功的捕捉,打印出它的警告信息。