本文采用Q&A形式整理归纳了 C# 入门重要概念与知识点,供学习参考。
不对之处欢迎批评指正。

1、.NET Framework和C#
1.1 .NET Framework是什么?
.NET Framework是一个平台,让开发人员能够以独立于语言和平台的方式创建并运行下一代应用程序和Web服务,还有助于消除(起码是减少)众多常见的编程错误。
1.2 公共语言运行时(CLR)是什么?
公共语言运行时(CLR)是.NET Framework的核心,而C#运行在.NET Framework之上。
1.3 托管应用程序和非托管应用程序之间有何不同?
针对.NET Framework编写的代码属于托管代码,其他所有代码都属于非托管代码。
1.4 垃圾收集是什么?它为何很重要?
垃圾收集是.NET Framework提供的一种运行阶段服务,让您无需手动分配和释放内存。这可避免众多常见的编程错误,让您创建的应用程序更正问题,还让您能够将主要精力放在应用程序所需的业务逻辑上。
1.5 C#是什么?
C#是一种面向对象编程语言,它是类型安全的,运行在.NET Framework之上。
1.6 C#程序会被编译吗?
会。在开发阶段,C#程序被编译成通用中间语言(CIL);在运行阶段,即时(JIT)编译器再将CIL编译成可执行的目标代码。
1.7 .NET Framework有哪些组件?
.NET Framework有 4个组件:公共语言运行时、Framework类库、并行计算平台和动态语言运行时。
1.8 为何说通用类型系统很重要?
因为它给每种.NET语言提供了相同的类型描述,并指定了类型的用法,可以集成不同的语言。
1.9 通用中间语言是什么?
通用中间语言是一种低级语言,对托管代码进行部分编译时,将生成这种语言的代码。可将通用中间语言视为汇编语言,由表示高级语言代码的低级指令组成。
1.10 为什么说类库很重要?
.NET类库提供了大量可重用的类型供所有.NET语言使用,这简化了众多常见的编程任务,从而提高了开发人员的效率。
1.11 动态语言运行时为C#提供了什么?
动态语言运行时让 C#能够以一致的语法使用来自任何地方( COM、IronRuby、IronPython、JavaScript等)的动态对象。
二、理解C#类型
2.1 静态类型意味着什么?
C#是一种静态类型语言,这要求您创建任何变量时,都必须将其数据类型告知编译器;而编译器将确保您只能将兼容的数据类型存储到变量中。
2.2 C#支持指针吗?
C#确实支持指针,但是指针并非其核心部分,您只能在不安全代码中使用指针。
2.3 在C#中,统一类型系统为何重要?
通过提供统一类型系统,C#让您能够将任何值类型作为 object,而不会带来不必要的开销。
2.4 所有预定义类型都符合CLS吗?
不,无符号整数类型和sbyte不符合CLS,但是必要时可使用符合CLS的类型替换它们。
2.5 使用var声明的变量是强类型的吗?
是的。使用 var 声明的变量仍是强类型的,因为编译器将在编译阶段指定这种变量的类型。var并不相当于Visual Basic类型中的Variant。
2.6 值类型和引用类型之间有何不同?
值类型变量直接存储数据,引用类型变量存储的是指向数据的引用。
2.7 值类型可以为null吗?
值类型分为可以为null的和不可以为null的。对于可以为null的值类型,取值范围为其底层类型的取值范围加上null;不可以为null的值类型不能为null。
2.8 为何应尽可能避免装箱和取消装箱操作?
因为它们将耗用大量资源,带来很大的开销。
2.9 C#类型分为几大类?
C#类型分引用类型、值类型和类型参数。
2.10 对金融计算而言,哪种预定义类型很重要?为什么?
decimal类型对金融计算来说很有用,它避免了其他浮点类型常见的表示误差。
2.11 哪种类型是所有预定义类型的基类?
归根结底,C#中的所有预定义类型及其他一切都是从object类型派生而来的。
2.12 为何单独提供布尔类型很重要?
通过包括单独的bool类型,消除了整数0和1带来的二义性,有助于避免多种常见的编程错误。
2.13 所有字符数据都以Unicode字符集存储吗?
是的,在C#中,所有字符串和字符都存储为Unicode,这有助于本地化。
2.14 字符串的不可变性意味着什么?
由于字符串是不可变的,因此赋值后就不能修改。这意味着每当执行字符串拼接操作时,都需要创建新的 string 对象来存储结果。如果在短时间内重复执行大量这样的操作,就可能导致内存占用率急剧上升,因此应考虑转而使用StringBuilder类。
2.15 前自增运算和候自增运算有何不同?
在前递增运算中,结果为递增之后的变量值;在后递增运算中,结果为递增之前的变量值。
2.16 null合并运算符(??)可用于引用类型和可以为null的值类型吗?
是的,null合并运算符可用于可包含null的任何类型,包括对象。
2.17 长整型可以隐式转换为整型吗?
不能将long隐式地转换为int,因为这将降低量级;但是可以显式地进行转换。
2.18 装箱的过程是怎样的?
将值类型用作引用类型时,将发生装箱操作,这需要新建一个实例来存储装箱后的值。对装箱得到的对象执行操作时,不会影响原来的值。
2.19 拆箱的过程是怎样的?
将引用类型(object)拆解转换为值类型,此过程称为拆箱,无论是装箱还是拆箱,都会降低程序性能,应尽可能避免装箱拆箱操作。
三、C#面向对象编程基础:类与对象
3.1 面向对象编程的四项基本原则是什么?
面向对象编程的四项基本原则是封装、抽象、继承和多态。
3.2 封装和抽象为何重要?
通过使用封装和抽象,可修改内部实现细节,而不会影响原有的使用类的代码。
3.3 方法重载是什么?
方法重载指的是在同一类内创建多个同名的方法,重载方法的签名不能相同。
3.4 属性如何让类满足封装的目标?
属性使得访问字段时就像它是公有的一样,同时让您能够隐藏字段的内部细节。
3.5 什么是部分类?
分部类的类声明中包含关键字partial,这种类通常分散在多个源代码文件中,便于协作开发。
3.6 使用扩展方法有何优点?
通过使用扩展方法,可给现有类型添加功能,而无需使用继承。随后,可以自然、直观的方式使用添加的功能。
3.7 C#有哪几个权限访问修饰符?
5个C#访问修饰符分别是 public、protected、internal、protected internal和private。
3.8 类的默认访问级别是什么?
类的默认访问级别为internal,但也可将其访问级别声明为public或internal。嵌套类的默认访问级别为private,但可将其声明为其他任何访问级别。
3.9 什么是构造方法?
构造方法是一种特殊的方法,每当您创建对象时都自动执行,以提供额外的初始化操作。
3.10 对象的默认构造方法能有参数吗?
不可以,对象的默认构造函数不能接受任何参数。
3.11 何时能给只读字段赋值?
只读字段只能在声明时初始化或在构造方法中对其进行初始化。
3.12 自动实现的属性是否有局限性?
自动实现的属性没有提供访问隐式支持字段的途径;您无法在访问器get或set中指定额外的语句;不能混合使用常规语法和自动实现语法。
3.13 什么是嵌套类?
嵌套类是完全嵌套在另一个类声明中的类,嵌套类不是子类。
3.14 扩展方法能够访问被扩展的类型的私有成员吗?
扩展方法只不过是静态方法,它对被扩展的类型没有特殊访问权限。然而,如果扩展方法是在被扩展的类型所属的程序集中定义的,那么它也能够访问该类型的internal成员。
3.15执行 new 运算符会发生什么?
执行new运算符时发生的两个主要操作是:从堆(heap)分配内存;执行类的构造函数以初始化分配的内存。
四、C#面向对象编程进阶:继承、接口与抽象类
4.1 类继承有什么作用?
类继承使得对象具有多态性并可串接基类构造函数。
4.2 C#支持多重继承吗?
不,C#只支持单继承,即只继承一个父类(基类)。
4.3 什么是多态?
多态指的是可将一种类型当作其他类型使用。
4.4 什么是向上转型和向下转型?
将派生类转换为基类称为向上转型,而将基类转换为派生类称为向下转型。
4.5 什么是成员隐藏?
成员隐藏让派生类成员可以与基类成员同名,且行为完全相同。
4.6 什么是虚成员?
虚成员是在基类中使用修饰符virtual声明的成员,它可能有默认行为,也可能没有。派生类可重写虚成员,并提供更合适的行为。
4.7 可禁止类被继承吗?
可以,使用修饰符sealed声明的类不能被继承。
4.8 什么是接口?
接口定义了一组没有实现的通用特征和行为,所有派生类都必须实现它们;所有接口成员都必须是公有的。接口不能保证实现是正确的,而只要求派生类必须包含签名与接口成员相同的成员。
4.9 C#支持多接口继承吗?
是的,C#支持继承多个接口。接口也可继承其他接口。
4.10 可使用扩展方法来扩展接口吗?
可以,可像扩展类一样使用扩展方法来扩展接口。
4.11 为何类继承也称为实现继承?
这是因为派生类继承基类的实现。
4.12要隐藏继承而来的成员,正确的方法是什么?
要隐藏继承而来的成员,应在声明派生成员时使用关键字new,以显式地指出您要隐藏基类成员。
4.13 对成员重写有哪些限制?
成员重写有如下限制:
(1) 在重写成员的声明中,不能修改给虚成员指定的访问级别。
(2) 虚成员和重写成员都不能声明为private级别。
(3) 虚成员和重写成员的签名必须相同。
(4) 声明重写成员时,不能使用修饰符new、static和virtual。
五、枚举类型与结构体
5.1 枚举类型和结构体分别有什么作用?
(1) 枚举类型让您能够定义一组离散的命名值。
(2) 结构体让您能够定义自己的轻量级值类型。
5.2 为什么说枚举类型很有用?
枚举类型让您能够定义一组离散的数值,并给这些值指定易于理解的名称(标识符)。这让您的代码更容易理解,还有助于确保代码是正确的。
5.3 可组合枚举值,以表示枚举类型中原本没有的值吗?
这可使用位标志枚举来实现。在位标志枚举中,显式定义的所有值都必须是2的幂。对于枚举中定义的值,可使用按位运算符OR进行组合,以得到枚举中原来没有的值。
5.4 结构是值类型还是引用类型?
虽然结构被视为轻量级类,但实际上是值类型。
5.5 枚举类型可使用哪些底层类型?
枚举可使用如下底层类型:byte、short、int、long、sbyte、ushort、uint和ulong。
5.6 未显式指定的情况下,枚举的默认底层类型是什么?
如果没有显式地指定,枚举就将使用底层类型int。
5.7 为枚举指定Flags(可组合标志位)特性有何作用?
通过给枚举指定特性Flags,可明确指出允许对枚举值进行组合以生成新值。这还将改变方法ToString在运行阶段的行为,使得对组合值调用该方法时,它将显示构成组合值的各个枚举值的名称。
5.8 结构体可否继承?
结构不支持继承,但可以继承接口。
5.9 结构体的构造方法能重载吗?
结构支持构造函数重载。
5.10 结构体可以有自定义的默认构造方法吗?
结构不能包含自定义的默认构造函数。您可以提供重载的构造函数,但是必须确保这种构造函数执行完毕时所有字段都初始化了。
六、C#委托与事件
6.1 事件有什么用?
事件可以让您创建交互性极强的应用程序,,事件不仅包括用户通过图形用户界面执行的操作,它还提供了丰富而复杂的通知系统,可供您创建的类使用。
6.2 什么是委托?
委托是一种类型安全的回调编写方式,类似于C + +函数指针和Delphi封装。通过使用委托,可封装指向方法的引用。调用被引用的方法时,无需在编译阶段知道将调用哪个方法。委托在调用方,而不是声明方的安全权限下运行。
6.3 什么是事件?
事件是任何外部刺激,如用户操作(单击鼠标或按键)、来自其他程序或程序其他部分的消息。
6.4 EventArgs类有何用途?
EventArgs 类用于存储事件数据。虽然可直接使用它,但是最好为事件派生一个新类,哪怕这个新类最初是空的。
6.5事件分哪两类?
事前事件和事后事件。事前事件是可撤销的,在对象的状态发生变化时引发;事后事件在对象的状态发生变化后引发。
6.6 最常见的事件声明方式是什么?使用这种方式有哪些缺点?
定义事件时,最常用的方式是使用字段语法。类包含大量事件时,尤其只有其中几个事件有订户时,这种语法需要为每个事件声明一个字段,这带来了大量不必要的开销。
6.7 使用属性语法声明事件时,需要使用哪两个访问器?
使用属性语法声明事件时,需要使用访问器add和remove。访问器add将委托加入列表,而remove访问器将委托从列表中删除。
6.8 引发事件的标准模式需要定义一个方法,对于非密封类的非静态事件,需要给该方法声明什么样的访问级别?
对于非密封类的非静态事件,应将引发事件的方法声明为protected和virtual的,这让派生类能够通过重写来处理事件。
6.9 为何要创建事件委托的临时备份?
创建委托的临时备份旨在避免一种可能的竞态条件:事件被重置为null,导致引发事件时出现运行阶段错误。
6.10 什么是Lambda表达式?
Lambda 表达式又称箭头函数是一种简洁的匿名委托编写方式,可用于任何可使用传统委托的地方。
6.11 Lambda表达式的底层委托类型是什么?
Lambda表达式是无类型的,因此没有底层类型,但是可将其隐式地转换为任何兼容的委托类型。
七、C#程序流程控制
7.1 程序是如何控制执行流程的?
程序是通过决策、根据条件重复执行代码以及无条件地跳转到其他部分实现流程控制的
流程控制语句非常重要,它给C#语言提供了强大的功能和灵活性,让应用程序能够解决大部分问题。
7.2 C#提供了哪几种流程控制语句?
C#提供了3种流程控制语句。
(1) 选择语句:让您能够根据表达式值从多条语句中选择一条语句并执行它。
(2) 迭代语句:根据表达式值重复执行语句,每次迭代时都重新计算该表达式的值。
(3) 跳转语句:无条件地跳转到指定的位置。
7.3 while语句和do语句之间有何不同?
while语句属于开始测试循环,而do语句属于结束测试循环。这意味着while循环体中的语句将执行零或多次,而do循环体中的语句至少会执行一次。
7.4 在switch语句中,可将相同的语句用于多个case标签吗?
可将相同的代码用于多个case标签,只要这些case标签之间没有其他语句。
7.5 switch语句可包含多个default标签吗?
switch语句只能包含一个default标签。
7.6 for语句的3个部分都必不可少吗?
for语句的每个部分都是可选的。
7.7 在复合语句块中声明的变量可在该语句外面使用吗?
不能,这是一个语句块局部变量,其作用域为复合语句内部。
7.8 跳转语句后面的语句是否会执行?
不会执行。跳转语句无条件地跳转到指定位置,因此在当前语句块内,位于跳转语句后面的语句都不会执行。
7.9 在迭代语句的循环体内,可使用跳转语句吗?
在所有迭代语句的循环体内,都可使用跳转语句。
八、字符串及处理字符串
8.1字符串是什么?
字符串的本质就是字符数组。
8.2 字符串是不可变的吗?
尽管C#的字符串是引用类型的,但字符串却是不可变的,任何修改字符串内容的操作都创建一个新字符串对象,而不修改原始字符串。
8.3 在字符串字面值前面加上@符号意味着什么?
@是原义字符串符号,导致C#编译器按字符原义处理字符串,即使它跨越多行或包含特殊字符。
8.4 使用StringBuilder有何优点?
StringBuilder类让您能够创建和操作可变字符串,最常用于在循环中拼接字符串,这样能够大幅度提升执行效率。
8.5 什么是字符串暂留?为什么使用它?
C#编译器使用字符串暂留来消除重复的字符串字面值,以便在运行阶段节省内存空间。
8.6 使用原义字符串时,必须对内部的双引号进行转义吗?
使用原义字符串时,唯一需要转义的字符是双引号,这让编译器能够判断字符串终止于何处。
8.7 更推荐使用哪种方式检查字符串是否为空?
测试字符串是否为空时,推荐使用静态方法String.IsNullOrEmpty。
8.8任何字符串操作函数都会创建一个新字符串吗?
由于字符串是不可变的,因此所有的字符串操作都将导致创建一个新的字符串。
8.9 为何更推荐在循环中使用StringBuilder类拼接字符串?
StringBuilder表示可变字符串,在循环中使用它来拼接字符串时,可避免每次迭代都创建一个临时字符串。
九、用数组与集合批量存储数据
9.1 数组是什么?
数组是最简单的集合类型,C #在语言层面直接支持。
它是一系列使用数字索引的对象,它们在编译阶段的类型都相同。
9.2 什么是集合类?
集合类型(如 List<T>Stack<T>)是一种更灵活的数据组织形式,让您能够创建自己的专用集合,与数组不同,数组的长度是固定的,但集合类通常可变长度。
9.3 什么是索引器?
索引器是一个特殊的属性,让您能够像访问数组那样访问类的数据。索引器实现的本质是对 [] 运算符进行了重载。其与属性又相同,也支持访问器,索引器是用签名而不是名称标识的,且必须是实例成员。
9.4 C#数组的索引从0还是1开始?
C#数组的索引从0开始。
9.5 C#数组可调整大小吗?
C#数组是不可变对象,不能更改长度,但是可使用静态方法Array.Resize间接地调整C#数组的大小,这将创建一个新的数组,并将旧数组的值复制到新数组中。
9.6 List<T>集合是什么?
List<T>是最常用的泛型集合,它类似于数组,但可根据需要动态地调整大小。
9.7 什么是字典(Dictionary<TKey,TValue>)?
字典是一种可包含重复元素的集合,可提供一组键到一组值的映射。
9.8 HashSet<T>SortedSet<T>之间有何不同?
HashSet<T>相当于数学意义上的集,而SortedSet<T>在插入和删除元素时保持排序,而不会影响性能。这两个类不禁止元素重复。
9.9 IEnumerable<T>接口是什么?
IEnumerable<T>扩展了IEnumerable,它通过暴露枚举器支持对集合进行简单迭代。提供这个接口旨在与非泛型集合兼容,如果非泛型集合实现了该接口,就可将其用于需要IEnumerable的任何地方。
9.10 什么是数组初始值设定项和集合初始值设定项?
数组初始值设定项和集合初始值设定项是一种特殊的语法,让您能够轻松地声明和初始化数组或集合。数组初始值设定项让您能够省略数组类型,而只需提供数组的值。集合初始值设定项让您能够直接提供每个元素的值,从而省略多次调用添加方法的代码。
9.11 如何给数组分配内存?
数组被隐式转换为 System.Array 实例,因此属于引用类型。对于指向数组的引用,将从托管堆给它分配内存;但对于数组元素,将根据其类型分配内存。
9.12 声明索引器时,可使用哪些修饰符?
可用于索引器的修饰符包括修饰符new、virtual、sealed、override、abstract以及4个访问修饰符的有效组合。
9.13 在什么情况下应使用Collection<T>而不是List<T>
List<T>不容易扩展,因为它没有虚成员供派生类重写以修改行为。Collection<T>有可重写的虚成员,因此在需要自定义集合的行为时,Collection<T>更合适。
9.14 迭代字典的元素时,返回的是什么对象?
迭代字典的元素时,将返回KeyValuePair<TKey, TValue>结构,它表示一个键及其关联的值。
9.15 IDictionary<TKey, TValue>扩展了哪个接口?
IDictionary<TKey, TValue>扩展了接口 ICollection<T>
9.16 IComparer<T>IEqualityComparer<T>之间有何不同?
IComparer<T>定义了一个用于比较两个对象的方法,而IEqualityComparer<T>提供了一种途径,让您能够给类型T下相等的定义。
十、使用异常捕获和处理错误
10.1 什么是异常?为什么要捕获和处理异常?
异常是意外错误导致的,如果不妥善处理,可能导致应用程序崩溃。
仅当能够采取有意义的措施时,才应捕获异常,这一点很重要。
C#编译器有助于按正确的顺序捕获异常:首先应当捕获最具体的异常,最后才来捕获公用一长。
10.2 在什么情况下应使用异常?
异常让您能够以清晰、简洁、安全的方式表示运行期间发生的故障,应在遇到意外的错误时使用,通常是类成员无法完成其功能时。
10.3 什么是未经处理的异常?
未经处理的异常指的是应用程序没有提供显式的代码对其进行处理的异常。
10.4 try-catch块是什么?
try-catch块是一个保护区域,包含一个或多个异常处理程序。
10.5 try-finally块是什么?
try-finally块是一个不包含异常处理程序的保护区域,它在退出try块时执行,即使发生了异常也如此。
10.6 哪个类是所有异常的基类?
System.Exception是所有异常的基类。
10.7 RuntimeWrappedException是什么?
其他语言(如C++)引发不是从System.Exception派生而来的异常时,为确保语言之间的兼容性,将把这种异常包装在RuntimeWrappedException中。
10.8 应在代码中处理ArgumentException(及其子类)或InvalidOperationException吗?
通常,ArgumentException(及其子类)和InvalidOperationException表示编码错误,最好在编译阶段修复这种错误,而不在应用程序中以编程方式处理它们。
10.9 什么是恶化状态异常?
恶化状态异常指的是在应用程序外发生的异常,这意味着运行进程的完整性可能遭到破坏。默认情况下,无法捕获恶化状态异常。
10.10 发生异常时,如果调用栈包含静态构造函数或静态字段的初始值设定项,那么结果将如何?
如果调用栈中包含静态构造函数或静态字段的初始值设定项,就将引发TypeInitializationException,其InnerException属性包含原始异常。
10.11 在什么情况下应处理异常?
一般而言,仅当能够采取有意义的措施时,才应捕获异常。因此,使用try-finally的频率比使用try-catch或try-catch-finally的频率高。
十一、泛型编程
11.1 泛型有什么用?
泛型(generic)编程方式(通过创建自定义泛型类型和使用现有的泛型集合)是一个灵活且功能强大的概念,让您只需编写一个实现,同时可确保类型安全。
它让您能够以可重用的方式解决问题,而不管使用的具体类型是什么。
11.2 泛型的最常见用途是什么?
泛型最常用于集合类和接口中,但是也可将其用于自定义类中。
11.3 使用泛型可避免哪些问题?
通过使用泛型,只需编写一个实现,同时可确保类型安全,并避免装箱和取消装箱操作。
11.4 C#泛型类似于Java泛型和C++模板吗?
虽然语法类似,但是实现不同。Java泛型是一种语言构造,运行阶段无法获悉泛型类型信息。C++模板是在编译阶段展开的,编译器负责为每个模板类型生成额外的代码。
11.5 什么是类型约束?
约束让您能够指定哪些类型可在编译阶段用作类型实参,并向编译器保证:对类型参数执行的任何运算符和方法都将获得支持。
11.6 非泛型类可包含泛型方法吗?
在泛型类和非泛型类中都可定义泛型方法。
11.7 对泛型接口来说,协变和逆变分别是什么?
可变性指的是只要其类型实参在赋值方面是兼容的,两个泛型类型在赋值方面也是兼容的。协变让接口方法的返回类型的派生程度可高于类型参数指定的类型,而逆变让接口方法的实参类型的派生程度可以低于类型参数指定的类型。
11.8 要检查泛型值是否相等,正确的方法是什么?
要检查泛型值是否相等,正确的方法是指定约束where T : IComparable<T>,并使用方法CompareTo进行值相等性判断。
11.9 什么是类型参数约束?
类型参数约束指的是将一个泛型参数用作另一个泛型参数的约束。
11.10 什么是封闭类型和开放类型?
(1) 开放类型:即没有给它的任何类型参数指定类型实参;
(2) 封闭类型:即给其所有类型参数都提供了类型实参。
十二、文件与流
12.1 什么是流?
流是一系列用字节表示的数据分组。数据流有底层存储介质(通常称为支持存储空间),它给流提供了源。
12.2 相对路径和绝对路径之间有何不同?
绝对路径指定了完整的位置,而相对路径只指定部分位置。使用相对路径时,将以当前位置作为起点来查找指定的文件。
12.3 二进制文件和文本文件之间有何不同?
二进制文件是字节流,而文本文件只包含文本数据。
十三、特性
13.1 什么是特性(Attribute)?
特性是一个类,用于给代码声明添加元数据。
13.2 特性有什么作用?
特性提供了一种简单而功能强大的方法,让您能够给应用程序添加元数据。
在.NET Framework 中大量使用了特性,用于调用非托管代码,描述类、方法和接口的 COM 属性,描述为持久化需要序列化哪些类成员,指定安全性需求,控制JIT编译器优化,等等。
13.3 特性的位置参数是什么?
特性的位置参数是必不可少的,且必须按特定顺序提供。它们由特性的构造函数定义。
13.4 如何创建自定义特性?
要创建自定义特性,可创建一个从Attribute派生而来的类。
十四、动态类型及语言互操作性
14.1 动态语言运行时和动态类型有什么作用?
通过增加动态语言运行时,极大地增加了.NET Framework可支持的语言数量;还让诸如C#等静态语言能够轻松地访问动态语言定义的对象。通过使用动态类型,可访问动态对象,且语法与访问静态对象几乎相同。
14.2 什么是动态类型?
动态类型是指其操作可绕过编译阶段类型检查,而在运行阶段解析的类型。
14.3 可创建自定义动态对象吗?
可以。要创建自定义动态对象,可从 DynamicObject 类派生或实现接口 IDynamic-MetaObjectProvider。
14.4 嵌入主互操作程序集类型有何好处?
通过只嵌入应用程序使用了的互操作类型,有助于缩小部署的规模,同时又不需要部署PIA。这还让您能够将COM中的对象视为动态的,从而极大地降低了使用COM API的复杂度。
14.5 动态类型的静态编译类型是什么?
在编译阶段,动态类型的静态类型为dynamic。

本文总结道这里,祝大家学习愉快!
有问题欢迎评论交流!

标签: 计算机, 入门, 编程, .NET, CSharp, 张赐荣

添加新评论