11. C#高级进阶

news/2025/1/12 3:50:48/

目录

# .NET API

一、C# 异常处理

1、try/catch语句

2、C# 中的异常类

3、自定义异常类

4、C# 抛出异常

二、C# 目录操作

1、DirectoryInfo 类

2、FileInfo 类

三、C# 文件读写

1、C# 中的 I/O 类

2、FileStream 类

3、C# 中文本文件的读取/写入

(1)StreamReader

(2)StreamWriter

4、C# 中二进制文件读写

(1)BinaryReader 类

(2)BinaryWriter 类

四、C# 特性

1、定义特性

2、预定义特性

(1)AttributeUsage

(2)Conditional

(3)Obsolete

3、自定义特性

(1)声明自定义特性

(2)构建自定义特性

(3)应用自定义特性

五、C# 反射

1、反射的用途

2、查看元数据

六、C# 属性

1、访问器

2、抽象属性


# .NET API

一、C# 异常处理

        在 C# 中,异常是在程序运行出错时引发的,所有异常都派生自 System.Exception 类。异常处理就是处理运行时错误的过程,通过异常处理可以使程序在发生错误时保持正常运行。

        C# 中的异常处理基于四个关键字构建,分别是:try、catch、finally 和 throw。

  • try:try 语句块中通常用来存放容易出现异常的代码,其后面紧跟一个或多个 catch 语句块;
  • catch:catch 语句块用来捕获 try 语句块中出现的异常;
  • finally:finally 语句块用于执行特定的语句,不管异常是否被抛出都会执行;
  • throw:throw 用来抛出一个异常;

1、try/catch语句

        假设一段代码会引发异常,则可以使用 try 和 catch 组合来捕获这个异常。举例如下:

try
{int a = 123;int b = 0;int x = a / b;
}
catch (Exception e)
{Console.WriteLine("捕获到的异常:{0}", e);
}
finally
{Console.WriteLine("finally 语句块中的代码!");
}
Console.ReadKey();

2、C# 中的异常类

        C# 中的异常类主要是从 System.Exception 类派生的。比如 System.ApplicationException 和 System.SystemException 就是从 System.Exception 类派生的。

  • System.ApplicationException 类支持由程序产生的异常,因此我们自定义的异常类都应继承此类;
  • System.SystemException 类是所有系统预定义异常的基类;

        下表中列举了一些从 Sytem.SystemException 类派生的预定义异常类:

异常类描述
System.IO.IOException处理 I/O 错误
System.IndexOutOfRangeException处理当方法引用超出数组范围的索引时产生的错误
System.ArrayTypeMismatchException处理当数组类型不匹配时产生的错误
System.NullReferenceException处理引用一个空对象时产生的错误
System.DivideByZeroException处理当除以零时产生的错误
System.InvalidCastException处理在类型转换期间产生的错误
System.OutOfMemoryException处理空闲内存不足产生的错误
System.StackOverflowException处理栈溢出产生的错误

3、自定义异常类

        除了可以使用系统预定义的异常类外,我们还可以自行定义异常类,自定义的异常类都应继承 System.ApplicationException 类。

class Program
{static void Main(string[] args){TestUserDefinedException test = new TestUserDefinedException();try{test.Validate(12);} catch (InvalidAgeException e){Console.WriteLine(e.Message);}Console.ReadKey();}
}public class InvalidAgeException : ApplicationException
{public InvalidAgeException(string message) : base(message){}
}public class TestUserDefinedException
{public void Validate(int age){if (18 > age){throw new InvalidAgeException("Sorry, Age must be greater than 18");}}
}

4、C# 抛出异常

        如果异常是直接或间接派生自 System.Exception 类,则可以在 catch 语句块中使用 throw 语句抛出该异常。throw 语句的语法格式如下所示:

catch (Exception e)

{
   ......
   throw e
}

二、C# 目录操作

        C# 中允许您使用各种目录和文件相关的类来操作目录和文件,比如 DirectoryInfo 类和 FileInfo 类。

1、DirectoryInfo 类

        DirectoryInfo 类派生自 FileSystemInfo 类。其中提供了各种用于创建、移动、浏览目录和子目录的方法。需要注意的是,该类不能被继承。

        下表列出了 DirectoryInfo 类中一些常用的属性和方法:

属性/方法描述
Attributes获取当前文件或目录的属性
CreationTime获取当前文件或目录的创建时间
Exists获取一个表示目录是否存在的布尔值
Extension获取表示文件扩展名部分的字符串
FullName获取目录或文件的完整路径
LastAccessTime获取当前文件或目录最后被访问的时间
Name获取此 DirectoryInfo 实例的名称
public void Create()创建一个目录
public DirectoryInfo CreateSubdirectory(string path)在指定的路径上创建子目录,指定的路径可以是相对于 DirectoryInfo 类的实例的路径
public override void Delete()如果为空的,则删除该 DirectoryInfo
public DirectoryInfo[] GetDirectories()返回当前目录的子目录
public FileInfo[] GetFiles()从当前目录返回文件列表

2、FileInfo 类

        FileInfo 类派生自 FileSystemInfo 类,其中提供了用于创建、复制、删除、移动、打开文件的属性和方法。与 DirectoryInfo 类相同,FileInfo 类也不能被继承。

        下表列出了 FileInfo 类中一些常用的属性和方法:

属性描述
Attributes获取当前文件的属性
CreationTime获取当前文件的创建时间
Directory获取文件所属目录的一个实例
Exists获取一个表示文件是否存在的布尔值
Extension获取表示文件存在的字符串
FullName获取文件的完整路径
LastAccessTime获取当前文件最后被访问的时间
LastWriteTime获取文件最后被写入的时间
Length获取当前文件的大小,以字节为单位
Name获取文件的名称
public StreamWriter AppendText()创建一个 StreamWriter,追加文本到由 FileInfo 的实例表示的文件中
public FileStream Create()创建一个文件
public override void Delete()永久删除一个文件
public void MoveTo(string destFileName)移动一个指定的文件到一个新的位置,提供选项来指定新的文件名
public FileStream Open(FileMode mode)以指定的模式打开一个文件
public FileStream Open(FileMode mode,FileAccess access)以指定的模式,使用 read、write 或 read/write 访问,来打开一个文件
public FileStream Open(FileMode mode,FileAccess access,FileShare share)以指定的模式,使用 read、write 或 read/write 访问,以及指定的分享选项,来打开一个文件
public FileStream OpenRead()创建一个只读的 FileStream
public FileStream OpenWrite()创建一个只写的 FileStream

举例:

// 创建一个 DirectoryInfo 对象
DirectoryInfo dir = new DirectoryInfo(@"C:\Users\Administrator\Desktop\cs");
Console.WriteLine("获取当前目录的属性: {0}", dir.Attributes);
Console.WriteLine("获取当前目录的创建时间: {0}", dir.CreationTime);
Console.WriteLine("获取当前目录是否存在: {0}", dir.Exists);
Console.WriteLine("获取当前文件扩展名部分的字符串: {0}", dir.Extension);
Console.WriteLine("获取当前目录的完整路径: {0}", dir.FullName);
Console.WriteLine("获取上次访问当前目录的时间: {0}", dir.LastAccessTime);
Console.WriteLine("获取 DirectoryIndiro 实例的名称: {0}", dir.Name);// 获取目录中的文件以及它们的名称和大小
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{Console.WriteLine("文件名称:{0} ,大小:{1}", file.Name, file.Length);
}

三、C# 文件读写

        文件是存储在磁盘中的具有特定名称和目录路径的数据集合。当我们使用程序对文件进行读取或写入时,程序会将文件以数据流(简称流)的形式读入内存中。流可以看作是通过通信路径传递的字节序列,主要分为输入流和输出流,输入流主要用于从文件读取数据(读操作),输出流主要用于向文件中写入数据(写操作)

1、C# 中的 I/O 类

        System.IO 命名空间中包含了各种用于文件操作的类。如下表所示:

I/O 类描述
BinaryReader从二进制流中读取原始数据
BinaryWriter以二进制格式写入原始数据
BufferedStream临时存储字节流
Directory对目录进行创建、删除、移动等操作(静态类)
DirectoryInfo用于对目录执行操作
DriveInfo获取驱动器的信息
File对文件进行操作
FileInfo用于对文件执行操作
FileStream用于文件中任何位置的读写
MemoryStream用于随机访问存储在内存中的数据流
Path对路径信息执行操作
StreamReader用于从字节流中读取字符
StreamWriter用于向一个流中写入字符
StringReader用于从字符串缓冲区读取数据
StringWriter用于向字符串缓冲区写入数据

2、FileStream 类

        FileStream 类在 System.IO 命名空间下,使用它可以读取、写入和关闭文件。创建 FileStream 类对象的语法格式如下所示:

FileStream <object_name> = new FileStream(<file_name>, <FileMode Enumerator>, <FileAccess Enumerator>, <FileShare Enumerator>);

参数说明如下:

  • object_name:对象名称;
  • file_name:文件路径(包含文件名);
  • FileMode:枚举类型,用来指定文件的打开方式,可选值如下:
    • Append:打开一个已有文件,并将光标放置在文件末尾。如果文件不存在,则创建文件;
    • Create:创建一个新文件。如果文件已存在,则将旧文件删除,然后创建新文件;
    • CreateNew:创建一个新的文件。如果文件已存在,则抛出异常;
    • Open:打开一个已有文件。如果文件不存在,则抛出异常;
    • OpenOrCreate:打开一个已有文件,如果文件不存在,则创建一个新的文件并打开;
    • Truncate:打开一个已有文件,然后将文件清空(删除原有内容)。如果文件不存在,则抛出异常;
  • FileAccess:枚举类型,用来设置文件的存取,可选值如下:
    • Read:对文件的读取访问权限,可以从文件读取数据; 
    • Write:对文件的写入访问权限,数据可以写入该文件;
    • ReadWrite:对文件的读取和写入访问权限,可以写入和从文件中读取数据;
  • FileShare:枚举类型,用来设置文件的权限,可选值如下:
    • Inheritable:使文件句柄由子进程继承,这是不直接支持 Win32;
    • None:拒绝共享当前文件。在关闭文件之前,任何请求打开的文件(此进程或另一个进程)将失败;
    • Read:允许以后打开文件进行读取。如果未指定此标志,则文件关闭前,任何打开该文件以进行读取的请求都将失败。需要注意的是,即使指定了此标志,仍需要附加权限才能够访问该文件;
    • Write:允许以后打开文件进行写入。如果未指定此标志,则文件关闭前,任何打开该文件以进行写入的请求都将失败,需要注意的是,即使指定了此标志,仍可能需要附加权限才能够访问该文件;
    • ReadWrite:允许以后打开的文件进行读取或写入。如果未指定此标志,则文件关闭前,任何打开该文件以进行读取或写入的请求都将失败,需要注意的是,即使指定了此标志,仍需要附加权限才能够访问该文件;
    • Delete:允许以后删除文件;

        FileStream 类中的常用方法如下所示:

方法描述
Close()关闭当前流并释放与之关联的所有资源(如套接字和文件句柄)
CopyTo(Stream)从当前流中读取字节并将其写入到另一流中
Dispose()释放由 Stream 使用的所有资源
Finalize()确保垃圾回收器回收 FileStream 时释放资源并执行其他清理操作
Flush()清除此流的缓冲区,使得所有缓冲数据都写入到文件中
Lock(Int64, Int64)

防止其他进程读取或写入 FileStream

Unlock(Int64, Int64)允许其他进程访问以前锁定的某个文件的全部或部分
Read(Byte[], Int32, Int32)从流中读取字节块并将该数据写入指定缓冲区
ReadByte()从文件中读取一个字节,并将读取位置提升一个字节
Write(Byte[], Int32, Int32)将字节块写入文件流
WriteByte(Byte)将一个字节写入文件流中的当前位置
Equals(Object)判断指定对象是否等于当前对象
ToString()返回表示当前对象的字符串
GetHashCode()默认哈希函数
GetType()获取当前实例的 Type

 举例:

// 使用 FileStream 类读取指定的文件:
FileStream file = new FileStream("test.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite);
for (int i = 0; i < 20; i++)
{file.WriteByte((byte)i);
}
// 设置文件流的位置
file.Position = 0;
for (int i = 0; i < 20; i++)
{Console.Write(file.ReadByte() + " ");
}
file.Close();
Console.ReadKey();

3、C# 中文本文件的读取/写入

        System.IO 命名空间下的 StreamReader 和 StreamWriter 类可以用于文本文件的读写操作。

(1)StreamReader

        StreamReader 类继承自抽象基类 TextReader,用于从特定编码的字节流中读取字符。下表列出了 该类中一些常用的方法: 

方法描述
public override void Close()关闭 StreamReader 对象和基础流,并释放任何与之相关的系统资源
public override int Peek()返回下一个可用的字符,但不使用它
public override int Read()从输入流中读取下一个字符,并把字符位置往前移一个字符

举例:

        使用 StreamReader 读取指定文件的内容。

try
{// 创建 StreamReader 类的对象StreamReader file = new StreamReader("test.txt");String line;// 从文件中读取内容while ((line = file.ReadLine()) != null){Console.WriteLine(line);}
} catch (Exception e)
{// 展示出错信息Console.WriteLine("无法读取文件");Console.WriteLine(e.Message);
}
Console.ReadKey();

(2)StreamWriter

        StreamWriter 类继承自抽象类 TextWriter,用于以特定编码将字符写入文件。下表列出了 StreamWriter 类中一些常用的方法:

方法描述
public override void Close()关闭当前 StreamWriter 对象和基础流
public override void Flush()清理当前所有缓冲区,并将所有缓冲区数据写入基础流
public override void Write(char value)将一个字符写入文本流
public override void Write(string value)将一个字符串写入文本流
public virtual void Write(bool value)将布尔值的文本表示形式写入文本流
public virtual void Write(decimal value)将一个小数值的文本表示形式写入文本流
public virtual void Write(double value)将一个 8 字节浮点值的文本表示形式写入文本流
public virtual void Write(int value)将一个 4 字节有符号整数的文本表示形式写入文本流
public virtual void WriteLine()将行结束符写入文本流

举例:

        使用 StreamReader 向文件中写入指定内容。

// 要写入文件中的数据
string[] str = new string[]{"百度一下","https://www.baidu.com","C# 教程"
};
// 创建 StreamWriter 类的对象
StreamWriter file = new StreamWriter("test.txt");
// 将数组中的数据写入文件
foreach (string s in str)
{file.WriteLine(s);
}
file.Close();
// 读取文件中的内容
string line;
StreamReader readfile = new StreamReader("test.txt");
while ((line = readfile.ReadLine()) != null)
{Console.WriteLine(line);
}
readfile.Close();
Console.ReadKey();

4、C# 中二进制文件读写

        System.IO 命名空间下的 BinaryReader 和 BinaryWriter 类可以用于二进制文件的读写。

(1)BinaryReader 类

        BinaryReader 类用于从文件读取二进制数据,常用方法如下所示:

方法描述
public override void Close()关闭 BinaryReader 对象和基础流
public virtual int Read()从基础流中读取字符,并根据所使用的编码和从流中读取的特定字符,将流的当前位置前移
public virtual bool ReadBoolean()从当前流中读取一个布尔值,并将流的当前位置前移一个字节
public virtual byte ReadByte()从当前流中读取下一个字节,并将流的当前位置前移一个字节
public virtual byte[] ReadBytes(int count)从当前流中读取指定数目的字节到一个字节数组中,并将流的当前位置前移指定数目的字节
public virtual char ReadChar()从当前流中读取下一个字符,并把流的当前位置按照所使用的编码和从流中读取的指定的字符往前移
public virtual char[] ReadChars(int count)从当前流中读取指定数目的字符,并以字符数组的形式返回数据,并把流的当前位置按照所使用的编码和从流中读取的指定的字符往前移
public virtual string ReadString()从当前流中读取一个字符串,字符串以长度作为前缀,同时编码为一个七位的整数
public virtual int ReadInt32()从当前流中读取一个 4 字节有符号整数,并把流的当前位置前移四个字节
public virtual double ReadDouble()从当前流中读取一个 8 字节浮点值,并把流的当前位置前移八个字节

(2)BinaryWriter 类

        BinaryWriter 类用于向文件写入二进制数据,常用方法如下表所示:

方法描述
public override void Close()关闭 BinaryWriter 对象和基础流
public virtual void Flush()清理当前编写器的所有缓冲区,并将所有缓冲数据写入基础设备
public virtual long Seek(int offset,SeekOrigin origin)设置当前流中的位置
public virtual void Write(bool value)将一个字节的布尔值写入到当前流中,0 表示 false,1 表示 true
public virtual void Write(byte value)将一个无符号字节写入到当前流中,并把流的位置前移一个字节
public virtual void Write(byte[] buffer)将一个字节数组写入到基础流中
public virtual void Write(char ch)将一个 Unicode 字符写入到当前流中,并把流的当前位置按照所使用的编码和要写入到流中的指定字符往前移
public virtual void Write(char[] chars)将一个字符数组写入到当前流中,并把流的当前位置按照所使用的编码和要写入到流中的指定字符往前移
public virtual void Write(string value)将一个有长度前缀的字符串按 BinaryWriter 的当前编码写如到流中,并把流的当前位置按照所使用的编码和要写入到流中的指定字符往前移
public virtual void Write(int value)将一个 4 字节有符号整数写入到当前流中,并把流位置前移四个字节
public virtual void Write(double value)将一个 8 字节浮点值写入到当前流中,并把流位置前移八个字节

举例:

        下面通过示例演示二进制文件的读取和写入:

BinaryWriter bw;
BinaryReader br;
int i = 25;
double d = 3.14157;
bool b = true;
string s = "C#教程";
// 创建文件
try
{bw = new BinaryWriter(new FileStream("mydata", FileMode.Create));
}
catch (IOException e)
{Console.WriteLine(e.Message + "\n 文件创建失败!");return;
}
// 写入文件
try
{bw.Write(i);bw.Write(d);bw.Write(b);bw.Write(s);
}
catch (IOException e)
{Console.WriteLine(e.Message + "\n 文件写入失败!");
}
bw.Close();// 读取文件
try
{br = new BinaryReader(new FileStream("mydata", FileMode.Open));
}
catch (IOException e)
{Console.WriteLine(e.Message + "\n 文件打开失败!");return;
}
try
{i = br.ReadInt32();Console.WriteLine("Integer data: {0}", i);d = br.ReadDouble();Console.WriteLine("Double data: {0}", d);b = br.ReadBoolean();Console.WriteLine("Boolean data: {0}", b);s = br.ReadString();Console.WriteLine("String data: {0}", s);
}
catch (IOException e)
{Console.WriteLine(e.Message + "\n 文件读取失败!.");
}
br.Close();Console.ReadKey();

四、C# 特性

        特性(Attribute)是一种用于在程序运行时传递各种元素(例如类、方法、结构、枚举等)行为信息的声明性代码。使用特性可以将元数据(例如编译器指令、注释、描述、方法和类等信息)添加到程序中。.Net Framework 提供了两种类型的特性,分别是预定义特性自定义特性

        在 C# 中,特性具有以下属性:

  • 使用特性可以向程序中添加元数据。元数据是指程序中各种元素的相关信息,所有 .NET 程序中都包含一组指定的元数据;
  • 可以将一个或多个特性应用于整个程序、模块或者较小的程序元素(例如类和属性)中;
  • 特性可以像方法和属性一样接受自变量;
  • 程序可使用反射来检查自己的元数据或其他程序中的元数据;

1、定义特性

        C# 中定义特性的语法格式如下所示:

[attribute(positional_parameters, name_parameter = value, ...)]

其中,

  [ ]用来定义特性的名称和值;

        positional_parameters 用来指定基本信息;

        name_parameter 用来指定可选信息;

2、预定义特性

        .Net Framework 中提供了三个预定义特性。

(1)AttributeUsage

        用来描述如何使用自定义特性类。其语法格式如下:

[AttributeUsage (
   validon,
   AllowMultiple = allowmultiple,
   Inherited = inherited
)]

★参数说明如下:

  • validon:用来定义特性可被放置的语言元素。它是枚举器 AttributeTargets 的值的组合。默认值是 AttributeTargets.All;
  • allowmultiple:可选参数。为 AllowMultiple 属性指定一个布尔值,默认值为 false(单用的),如果为 true,则该特性是多用的;
  • inherited:可选参数。为 Inherited 属性指定一个布尔值,默认为 false(不被继承),如果为 true,则该特性可被派生类继承;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Method |AttributeTargets.Property, AllowMultiple = true)]

(2)Conditional

        用来标记一个方法,它的执行依赖于指定的预处理标识符。根据该特性值的不同,在编译时会起到不同的效果。例如:当值为 Debug 或 Trace 时,会在调试代码时显示变量的值。预定义特性 Conditional 的语法格式如下:

[Conditional(
    conditionalSymbol
)]

        举例:预定义特性 Conditional 的使用:

#define DEBUG
using System;
using System.Diagnostics;namespace MyFirstConsoleApp
{class Program{static void Function1(){MyClass.Message("Function1 函数");Function2();}static void Function2(){MyClass.Message("Function2 函数");}static void Main(){MyClass.Message("Main 函数!");Function1();Console.ReadKey();}}public class MyClass{[Conditional("DEBUG")]public static void Message(string msg){Console.WriteLine(msg);}}
}

(3)Obsolete

        用来标记不应被使用的程序元素。例如:当我们需要使用一个新方法来替代类中的某个旧方法时,就可以使用该特性将旧方法标记为 obsolete(过时的)并输出一条消息,来提示我们应该使用新方法代替旧方法。预定义特性 Obsolete 的语法格式如下:

[Obsolete (
   message,
   iserror
)]

语法说明如下:

  • message:使用一个字符串,来描述项目为什么过时以及应该使用什么替代;
  • iserror:默认值是 false(编译器会生成一个警告),如果为 true,那么编译器会把该项目当作一个错误;

举例:预定义特性 Obsolete 的使用:

using System;namespace MyFirstConsoleApp
{class Program{[Obsolete("OldMethod 已弃用,请改用 NewMethod", true)]static void OldMethod(){Console.WriteLine("已弃用的函数");}static void NewMethod(){Console.WriteLine("新定义的函数");}static void Main(string[] args){OldMethod();}}
}

3、自定义特性

        自定义特性可以用于存储声明性的信息,还可以在运行时被检索。创建并使用自定义特性可以分为四个步骤:

  • 声明自定义特性;
  • 构建自定义特性;
  • 在目标程序上应用自定义特性;
  • 通过反射访问自定义特性;

(1)声明自定义特性

        自定义特性应该继承 System.Attribute 类,如下所示:

// 声明一个名为 DeBugInfo 的自定义特性

[AttributeUsage(
   AttributeTargets.Class |
   AttributeTargets.Constructor |
   AttributeTargets.Field |
   AttributeTargets.Method |
   AttributeTargets.Property,
   AllowMultiple = true)]


public class DeBugInfo : System.Attribute

(2)构建自定义特性

        构建一个名为 DeBugInfo 的自定义特性,该特性可以存储下面列举的调试信息:

  • bug 的代码编号;
  • bug 的开发人员名字;
  • 上次审查代码的日期;
  • 开发人员标记的字符串消息;

想定:

        DeBugInfo 类中有三个用于存储前三个信息的私有属性和一个用于存储消息的公有属性。所以前三个属性是 DeBugInfo 类的必需的定位( positional)参数,而消息则是一个可选的命名(named)参数。每个特性都至少有一个构造函数,而且定位( positional)参数需要通过构造函数传递。

(3)应用自定义特性

        通过把特性放置在紧挨着它的目标上面来应用该特性,示例代码如下:

using System;namespace MyFirstConsoleApp
{class Program{static void Main(){Rectangle rec = new Rectangle(12, 15);rec.Display();Console.ReadKey();}}[DebugInfo(45, "Zara Ali", "12/8/2012", Message = "返回值类型不匹配")][DebugInfo(49, "Nuha Ali", "10/10/2012", Message = "未使用变量")]class Rectangle{// 成员变量protected double length;protected double width;public Rectangle(double l, double w){this.length = l;this.width = w;}[DebugInfo(55, "Zara Ali", "19/10/2012", Message = "返回值类型不匹配")]public double GetArea(){return length * width;}[DebugInfo(56, "Zara Ali", "19/10/2012")]public void Display(){Console.WriteLine("Length: {0}", length);Console.WriteLine("Width: {0}", width);Console.WriteLine("Area: {0}", GetArea());}}[AttributeUsage(AttributeTargets.Class |AttributeTargets.Constructor |AttributeTargets.Field |AttributeTargets.Method |AttributeTargets.Property,AllowMultiple = true)]public class DebugInfo : System.Attribute{private readonly int bugNo;private readonly string developer;private readonly string lastReview;public string message;public DebugInfo(int bg, string dev, string d){this.bugNo = bg;this.developer = dev;this.lastReview = d;}public int BugNo{get{return bugNo;}}public string Developer{get{return developer;}}public string LastReview{get{return lastReview;}}public string Message{get{return message;}set{message = value;}}}
}

五、C# 反射

        反射(Reflection)是指程序可以访问、检测和修改它本身状态或行为的一种能力。反射中提供了用来描述程序集、模块和类型的对象,可以使用反射动态地创建类型的实例,并将类型绑定到现有对象,或者从现有对象中获取类型,然后调用其方法或访问其字段和属性。如果代码中使用了特性,也可以利用反射来访问它们。

1、反射的用途

        C# 中反射具有以下用途:

  • 在运行时查看视图属性信息;
  • 检查装配中的各种类型并实例化这些类型;
  • 在后期绑定到方法和属性;
  • 在运行时创建新类型,然后使用这些类型执行一些任务;

2、查看元数据

        前面我们提到了可以使用反射查看特性的信息,下面就来看一下具体的操作步骤。首先需要初始化 System.Reflection 类的 MemberInfo 对象,用来发现与类关联的属性,例如:

System.Reflection.MemberInfo info = typeof(MyClass);

举例:

using System;
using System.Reflection;namespace MyFirstConsoleApp
{class Program{static void Main(){Rectangle rec = new Rectangle(4.5, 7.5);rec.Display();Type type = typeof(Rectangle);// 遍历 Rectangle 类的属性foreach (object attributes in type.GetCustomAttributes(false)){DebugInfo dbi = (DebugInfo)attributes;if (null != dbi){Console.WriteLine("Bug 编号: {0}", dbi.BugNo);Console.WriteLine("开发者: {0}", dbi.Developer);Console.WriteLine("上次审核时间: {0}", dbi.LastReview);Console.WriteLine("评论: {0}", dbi.Message);}}// 遍历函数属性foreach (MethodInfo m in type.GetMethods()){foreach (object attributes in m.GetCustomAttributes(true)){if (attributes is DebugInfo dbi){Console.WriteLine("Bug 编号: {0}, 函数名: {1}", dbi.BugNo, m.Name);Console.WriteLine("开发者: {0}", dbi.Developer);Console.WriteLine("上次审核时间: {0}", dbi.LastReview);Console.WriteLine("评论: {0}", dbi.Message);}}}Console.ReadKey();}}[DebugInfo(45, "Zara Ali", "12/8/2012", Message = "返回值类型不匹配")][DebugInfo(49, "Nuha Ali", "10/10/2012", Message = "未使用变量")]class Rectangle{// 成员变量protected double length;protected double width;public Rectangle(double l, double w){this.length = l;this.width = w;}[DebugInfo(55, "Zara Ali", "19/10/2012", Message = "返回值类型不匹配")]public double GetArea(){return length * width;}[DebugInfo(56, "Zara Ali", "19/10/2012", Message = "返回值类型不匹配")]public void Display(){Console.WriteLine("Length: {0}", length);Console.WriteLine("Width: {0}", width);Console.WriteLine("Area: {0}", GetArea());}}[AttributeUsage(AttributeTargets.Class |AttributeTargets.Constructor |AttributeTargets.Field |AttributeTargets.Method |AttributeTargets.Property,AllowMultiple = true)]public class DebugInfo : System.Attribute{private readonly int bugNo;private readonly string developer;private readonly string lastReview;public string message;public DebugInfo(int bg, string dev, string d){this.bugNo = bg;this.developer = dev;this.lastReview = d;}public int BugNo{get{return bugNo;}}public string Developer{get{return developer;}}public string LastReview{get{return lastReview;}}public string Message{get{return message;}set{message = value;}}}
}

六、C# 属性

        属性是类、结构体、接口的成员。类或结构体中的成员变量称为字段,属性是字段的扩展,使用访问器可以读写私有字段的值。

1、访问器

        属性访问器有两种,分别是 get 属性访问器和 set 属性访问器。其中 get 属性访问器用来返回属性的值,set 属性访问器用来为属性设置新的值。在声明属性访问器时可以仅声明其中一个,也可以两个同时声明。

举例:

using System;namespace MyFirstConsoleApp
{class Program{public static void Main(){// 创建一个新的 Student 对象Student s = new Student{// 设置 student 的 code、name 和 ageCode = "001",Name = "Zara",Age = 9};Console.WriteLine("学生信息: {0}", s);// 增加年龄s.Age += 1;Console.WriteLine("学生信息: {0}", s);Console.ReadKey();}}public class Student{private string code;private string name;private int age;// 声明类型为 string 的 Code 属性public string Code{get{return code;}set{code = value;}}// 声明类型为 string 的 Name 属性public string Name{get{return name;}set{name = value;}}// 声明类型为 int 的 Age 属性public int Age{get{return age;}set{age = value;}}public override string ToString(){return "编号 = " + code + ", 姓名 = " + name + ", 年龄 = " + age;}}
}

2、抽象属性

        抽象类中可以拥有抽象属性,这些属性会在派生类中实现。如:

using System;namespace MyFirstConsoleApp
{class Program{public static void Main(){// 创建一个新的 Student 对象Student s = new Student{// 设置 student 的 code、name 和 ageCode = "001",Name = "Zara",Age = 9};Console.WriteLine("学生信息: {0}", s);// 增加年龄s.Age += 1;Console.WriteLine("学生信息: {0}", s);Console.ReadKey();}}public abstract class Person{public abstract string Name{get;set;}public abstract int Age{get;set;}}public class Student : Person{private string code;private string name;private int age;// 声明类型为 string 的 Code 属性public string Code{get{return code;}set{code = value;}}// 重写基类的 Name 属性public override string Name{get{return name;}set{name = value;}}// 重写基类的 Age 属性public override int Age{get{return age;}set{age = value;}}public override string ToString(){return "编号 = " + code + ", 姓名 = " + name + ", 年龄 = " + age;}}
}

http://www.ppmy.cn/news/37059.html

相关文章

java调用python方法及常用的java调用python代码

Python语言作为一种流行的高级编程语言&#xff0c;在 Java开发中也是经常被使用到的。那么在 Java中如何调用 Python呢&#xff1f; 1、首先我们要知道&#xff0c; Java是一门面向对象的语言&#xff0c;所以我们可以通过方法和属性来调用 Python。 2、方法&#xff1a; &…

个人百度百科词条创建怎么收费?

互联网时代&#xff0c;百科营销起到举足轻重的作用&#xff0c;因为现在几乎人人都会在百度上去搜索答案&#xff0c; 当用户不了解你的时候&#xff0c;考虑是否和你合作的时候&#xff0c;也会下意识地去百度上搜索一下&#xff0c;看看有没有相关介绍。 这个时候创建一个百…

SolidWorks 2018版本介绍

solidwords 2018介绍SolidWorks 2018安装包SolidWorks 2018安装过程1、SolidWorks 2018 的介绍2、SolidWorks 2018 的特点3、SolidWorks 2018 的功能4、SolidWorks 2018快捷键SolidWorks 2018安装包 链接&#xff1a;https://pan.baidu.com/s/14TUadlx6KHcJmXev8LhakA 提取码&a…

TC275-点亮属于AutoSAR的灯之MCAL配置

前面 前段时间算是通过S32K144这个芯片对AutoSAR开发的大概流程有了一个了解&#xff0c;但苦于最后代码集成和编译器配置上的烦恼&#xff0c;所以决定换一个平台来进行开发&#xff08;有教程&#xff0c;手动狗头&#xff09;。 英飞凌的Aurix系列——TC275。 配置 Reso…

2023年全国最新高校辅导员精选真题及答案34

百分百题库提供高校辅导员考试试题、辅导员考试预测题、高校辅导员考试真题、辅导员证考试题库等&#xff0c;提供在线做题刷题&#xff0c;在线模拟考试&#xff0c;助你考试轻松过关。 72.心理发展的特点是&#xff08;&#xff09;。 A.方向性与不可逆性 B.连续性与阶段性…

华为OD机试用java实现 -【删除重复数字后的最大数字】(2023-Q1 新题)

最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧本篇题解:删除重复数字后的最大数字 题…

vue集成tui.calendar日历组件

vue集成tui.calendar日历组件前言一、简介、效果图二、vue简单集成(集成js版本,没有使用官方的vue2版本)1.引包2.简单示例三、自定义功能1.需求分析、效果展示2.实现思路前言 vue2的集成在git上官方已经给出了demo这里就不贴代码了。本次主要是vue3集成 最近有个功能需要一个日…

无线耳机哪个品牌好?四大国内蓝牙耳机品牌排行

现今&#xff0c;蓝牙耳机越来越成为人们外出必备的数码产品之一。随着蓝牙耳机品牌的增多&#xff0c;多种多样的蓝牙耳机出现在大众视野&#xff0c;而国产蓝牙耳机凭借更高的性价比而受到不少用户的欢迎。接下来&#xff0c;我来给大家推荐四款国产的蓝牙耳机&#xff0c;一…