一、struct结构体
[访问修饰符]struct 结构体名字
{
结构体成员
}
结构体的使用场景
- [ 电脑的内存分为堆内存和栈内存。堆内存空间远大于栈内存,但是栈内存执行效率却高于堆内存 ]
- [ 引用类型保存在堆内存中,而值类型则保存在栈内存 ]
- [ class对象是引用类型,保存在堆内存中,执行效率比较低 ]
- [ struct是值类型,保存在内存中,运行效率高 ]
class的使用场景
- [ 抽象的概念、或者需要多个层级来表现对象关系 ]
- [ 适用于结构复杂的数据 ]
结构体的特点
- [ 可带有方法、字段、索引、属性、运算符方法和事件 ]
- [ 结构不能定义无参的默认构造方法 ]
- [ 结果可实现接口,但他不能继承,也不能被继承 ]
- [ 实例化可以使用new(),但也可以不使用new() ]
struct Game
{
public string name;
public string developer;
public DateTime releaseDate;
public Game(string name, string developer, DateTime date)
{
this.name = name;
this.developer = developer;
this.releaseDate = date;
}
public void GetInfo()
{
Console.WriteLine("游戏名称 "+ name);
Console.WriteLine("developer "+ developer);
Console.WriteLine("date "+ releaseDate);
}
}
class Program
{
static void Main(string[] args)
{
Game game;
game.name = "pokemon";
game.developer = "Crackpot";
game.releaseDate = DateTime.Today;
//必须需要全部成员变量初始化之后,才能调用
game.GetInfo();
Console.Read();
}
}
二、枚举
枚举的每一个项不可改变,其对应数值逐次累加
enum Weekday
{
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SATURDAYS,
SUNDAY,
}
class Program
{
static void Main(string[] args)
{
Weekday friday = Weekday.FRIDAY;
Console.WriteLine(friday.ToString());//输出为FRIDAY
Console.WriteLine((int)friday);//输出为4
var friday2 = (Weekday)4;
Console.WriteLine(friday2);
Weekday day = Weekday.SUNDAY;
switch (day)
{
case Weekday.MONDAY:
case Weekday.TUESDAY:
case Weekday.WEDNESDAY:
case Weekday.THURSDAY:
case Weekday.FRIDAY:
Console.WriteLine("今天要上班 啊");
break;
case Weekday.SATURDAY:
case Weekday.SUNDAY:
Console.WriteLine("休息 吧");
break;
}
Console.Read();
}
}
三、泛型(generic)
Program.cs
//where T : IComparable
//where T : class (product, book)
//where T : struct
//where T : new()
public class Utility<T> where T : IComparable, new()
{
public void DoSomething()
{
var obj = new T();
}
public int FindMax(int a, int b)
{
return a > b ? a : b;
}
public T FindMax(T a, T b)
{
return a.CompareTo(b) > 0 ? a : b;
}
}
class Program
{
static void Main(string[] args)
{
//var numberlist = new List();
var numberlist = new GenericList<int>();
numberlist.Add(1);
numberlist.Add(2);
//var productlist = new Productlist();
var productList = new GenericList<Product>();
productList.Add(new Product()
{
Id = 1,
Price = 100
});
productList.Add(new Product()
{
Id = 2,
Price = 200
});
var database = new Dictionary<string, Product>();
database.Add("123", new Product() { Id = 3, Price = 50 });
database.Add("234", new Product() { Id = 4, Price = 40 });
database.Add("345", new Product() { Id = 5, Price = 10 });
//Product product;
//database.TryGetValue("123", out product);
Product product = database.Get("123");
Nullable<int> number = new Nullable<int>();
Console.WriteLine(number.HasValue);
var number2 = new Nullable<int>(5);
number2.GetValueOrDefault();
Console.Read();
}
}
Product.cs
public class DiscountCalculator<T> where T : Product
{
}
public class Product
{
public int Id { get; set; }
public decimal Price { get; set; }
}
Nullable.cs
public class Nullable<T> where T : struct
{
private object _value;
public Nullable()
{
}
public Nullable(T value)
{
_value = value;
}
public bool HasValue
{
get { return _value != null; }
}
public T GetValueOrDefault()
{
if (HasValue)
{
return (T)_value;
}
return default(T);
}
}
ProductList.cs
public class ProductList
{
public void Add(Product order)
{
throw new NotImplementedException();
}
public Product this[int index]
{
get { throw new NotImplementedException(); }
}
}
public class GenericList<T>
{
public void Add(T order)
{
throw new NotImplementedException();
}
public T this[int index]
{
get { throw new NotImplementedException(); }
}
}
public class Dictionary<TKey, TValue>
{
public void Add(TKey key, TValue value)
{
throw new NotImplementedException();
}
public TValue Get(TKey key) { throw new NotImplementedException(); }
}
public class OrderList
{
public void Add(object order)
{
throw new NotImplementedException();
}
public object this[int index]
{
get { throw new NotImplementedException(); }
}
}
Book.cs
public class Book : Product
{
public string ISBN { get; set; }
}
List.cs
public class List
{
public void Add(int number)
{
throw new NotImplementedException();
}
public int this[int index]
{
get { throw new NotImplementedException(); }
}
}
四、空处理
在C#中,值对象不能为null
声明值对象,C#编译器会赋予默认的初始化数据
- 布尔默认false
- 整数默认0
- 浮点数默认0
示例1
class Program
{
static void Main(string[] args)
{
//Nullable<DateTime> date = null; Nullable的代码可以简化为如下
DateTime? date = null;
Console.WriteLine(date.HasValue);
Console.WriteLine(date.GetValueOrDefault());
Console.WriteLine(date.Value);
Console.Read();
}
}
输出结果:

可以看到,HasValue的默认空输出为False,表明date变量不包含任何数据;
而GetValueOrDefault则给出一个Datetime默认为空的值;
第三行Value报错,报错信息为
因此,在访问可空数据时,使用GetValueOrDefault()是更加安全的
示例2
代码1
DateTime? date = new DateTime(2099,1,1);
if (date3.HasValue)
{
Console.WriteLine(date3.GetValueOrDefault());
}
else
{
Console.WriteLine(DateTime.Today);
}
代码2
DateTime? date = new DateTime(2099,1,1);
var result = date3 ?? DateTime.Today;//Coalescing Operator合并运算
Console.WriteLine(result);
可以看到代码1和代码2 的执行结果完全一样,因此推荐使用代码2的合并运算“??”来简化代码
五、拓展方法Extension
允许我们向一个已经存在的class中添加拓展代码
- [ 不需要修改原class ]
- [ 不需要继承原class ]
class Program
{
static void Main(string[] args)
{
string hello = "Hello World";
Console.WriteLine(hello.ShortTerm(3));
Console.Read();
}
}
public static class StringExtension
{
public static string ShortTerm(this string text, int number)//this string text代表需要被使用的字符串对象
{
return text.Substring(0, number);//SubString为切割字符串
}
}
六、动态类型dynamics
| 强语言 | 强语言 | ||
|---|---|---|---|
| 动态语言 | Erlang, Groovy, Clojure, Ruby, Python, Magik | C#, Scala, Java, F#, Haskell | 静态语言 |
| Dynamic | Perl, PHP, VB, JavaScript | C, C++ | Static |
| 弱语言 | 弱语言 |
class Program
{
public class Excel
{
public string Table { get; set; }
public void ShowTable()
{
Console.WriteLine("打印出来表格");
}
static void Main(string[] args)
{
object excel = new Excel();
//如何调用excel.ShowTable()方法
//方法1,使用反射
var methodInfo = excel.GetType().GetMethod("ShowTable");
methodInfo.Invoke(excel, null);
//方法2,使用dynamic
dynamic excel2 = new Excel();
excel2.ShowTable();
Console.Read();
}
}
}
使用动态类型dynamic,程序只有运行到这一行时,才对数据类型进行检查,与var是具有本质区别的,使用var定义,在定义时,其实已经确定了此时的变量类型
七、反射与元数据
实例化对象,但不使用new,不知道目标对象类型
元数据(Metadata)
公式:meta+A=关于A的A
如:元数据=关于数据的数据
数据库的数据、文件上的数据
运行中,查看或使用元数据的过程成为反射
反射的过程,元数据保存在程序集(Assembly)中
Program.cs
public class Program
{
static void Main(string[] args)
{
string classLocation = "Nullables.List,Nullables";
Type objType = Type.GetType(classLocation);
object obj = Activator.CreateInstance(objType);
MethodInfo add = objType.GetMethod("Add");
add.Invoke(obj, null);
Console.Read();
}
}
List.cs
public class List
{
public void Add()
{
Console.WriteLine("打印点什么");
}
}
反射的特点
- [ 不使用new关键词,我们也可以同样实例化对象 ]
- [ 不使用new关键词,意味着可以对系统进行进一步解耦 ]
反射的应用场景
- [ 单元测试、反转控制、依赖注入、泛型 ]
- [ 反射机制是.net框架中处于一个比较底层的位置 ]
- [ 一般不会直接接触 ]
代码示例
创建一个模拟计算机读取USB接口设备过程的项目
创建一个Computer.SDK类库
namespace Computer.SDK
{
public interface IUSB
{
void GetInfo();
void Read();
void Write();
}
}
创建一个Computer项目,依赖项引入Computer.SDK
namespace Computer
{
class Program
{
static void Main(string[] args)
{
string USBInterface = Path.Combine(Environment.CurrentDirectory, "USB");
Console.WriteLine(USBInterface);
var dllFiles = Directory.GetFiles(USBInterface);
var deviceList = new List<IUSB>();
foreach (var dll in dllFiles)
{
var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(dll);
var typeList = assembly.GetTypes();
foreach (var type in typeList)
{
var interfaceList = type.GetInterfaces();
foreach(var i in interfaceList)
{
if(i.Name == "IUSB")
{
var usb = (IUSB)Activator.CreateInstance(type);
deviceList.Add(usb);
}
}
}
}
foreach (var device in deviceList)
{
device.GetInfo();
device.Read();
device.Write();
}
Console.Read();
}
}
}
创建一个FlashDisk项目,依赖项引入Computer.SDK
namespace FlashDisk
{
public class FlashDisk : Computer.SDK.IUSB
{
public void GetInfo()
{
Console.WriteLine("128 G U盘");
}
public void Read()
{
Console.WriteLine("读取U盘数据");
}
public void Write()
{
Console.WriteLine("写入U盘数据");
}
}
}
创建一个SSDk项目,依赖项引入Computer.SDK
namespace SSD
{
public class SSD : Computer.SDK.IUSB
{
public void GetInfo()
{
Console.WriteLine("1 TB 固态硬盘");
}
public void Read()
{
Console.WriteLine("读取固态硬盘");
}
public void Write()
{
Console.WriteLine("写入固态硬盘");
}
}
}
在Computer->bin->Dibug->net8.0文件中创建USB文件夹
生成SSD和FlashDisk项目,分别进入这两个项目中的SSD(和FlashDisk)->bin->Dibug->net8.0->文件中,将SSD.dll和FlashDisk.dll项目复制粘贴到Computer->bin->Dibug->net8.0->USB文件中
完成后,此时执行项目,可以看到读取到“插入”至计算机USB接口的SSD以及FlashDisk
八、异常处理
例如
public class Calcultor
{
public int devide(int numerator, int denomenator)
{
return numerator / denomenator;
}
}
class Program
{
public static void Main(string[] args)
{
try
{
var calcultor = new Calcultor();
var resule = calcultor.devide(5, 0);
//Exception > SystemException > ArithmeticException > DivideByZeroException
}
catch(DivideByZeroException ex)
{
Console.WriteLine("除数不能为0");
}
catch(ArithmeticException ex)
{
Console.WriteLine("算数出错");
}
catch (Exception ex)
{
Console.WriteLine("运行出错");
//throw new Exception();抛出异常到上一层
}
finally//百分之百执行
{
}
Console.Read();
}
}
关于finally的使用,例如在try catch中,由于异常中断了运行,此时一些资源就需要手动进行回收
finally作为最后的守护,其中的代码一定会被执行
例如,在桌面创建一个123.txt的文件
public class Calcultor
{
public int devide(int numerator, int denomenator)
{
return numerator / denomenator;
}
}
class Program
{
public static void Main(string[] args)
{
StreamReader reader = null;
try
{
string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string filePath = Path.Combine(desktopPath, "123.txt");
reader = new StreamReader(filePath);
reader.ReadToEnd();
//人为制造异常
throw new Exception("出现状况了");
reader.Dispose();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
if(reader != null)
{
reader.Dispose();
Console.WriteLine("文件已经回收");
}
}
Console.Read();
}
}
本文详细介绍了C#的高级编程特性,包括struct结构体、枚举、泛型、空处理、拓展方法、动态类型dynamics、反射与元数据以及异常处理。结构体作为值类型在栈内存中存储,效率较高;枚举的每个项不可变且数值逐次累加;泛型提高了代码复用性;空处理中,推荐使用GetValueOrDefault()访问可空数据;拓展方法允许向现有类添加功能而不修改原类;动态类型dynamic在运行时检查数据类型;反射用于在运行时获取类信息,可用于单元测试等;异常处理中,finally块确保关键代码执行。



5万+

被折叠的 条评论
为什么被折叠?



