一、函数/功能成员(function member)
(1)概念
函数成员是包含可执行语句的那些成员;函数成员始终是类型的成员,而不能是名字空间的成员。
C#的函数成员包括的类别(category):方法、属性、事件、索引器、用户定义的操作符、实例构建器、静态构建器、析构器。
~除了不能显式调用静态构建器和析构器,其它都可通过函数成员调用(function member invocation,简为fmi)来执行。函数成员调用的实际书写语法,取决于特定的函数成员类别;
~fmi的自变量(argument)列表,为函数成员的参数(parameter)提供了实际值或变量引用(variable references);
~方法、索引器、操作符和实例构建器的调用采取重载方案(resolution)以确定调用函数成员的哪一个候选集(candidate set);
~编译时,一旦(once)某个特定的函数成员被识别(identified)出,就可能通过重载方案,执行调用函数成员的实际运行时处理,此过程不在这里详述;
~下面摘要了能够被显式调用的六个类别的函数成员--发生在构造内(in construct)的处理(e,x,y和value代表归类为变量或值的表达式,T代表归类为类型的表达式,F是方法的简单名称,P是属性的简单名称):
a.方法调用
~F(x, y) 应用重载决策以在包含类或结构中选择最佳的方法 F。用参数列表 (x, y) 调用该方法。如果该方法不为 static,则用 this 来表达对应的实例。
~T.F(x, y) 应用重载决策以在类或结构 T 中选择最佳的方法 F。如果该方法不为 static,则发生编译时错误。用参数列表 (x, y) 调用该方法。
~e.F(x, y) 应用重载决策以从e所属的类型确定的类、结构或接口中选择最佳的方法 F。如果该方法为 static,则发生编译时错误。用实例表达式e和参数列表 (x, y) 调用该方法。
b.属性访问
~P 调用包含类或结构中属性 P 的 get 访问器。如果 P 是只写的,则发生编译时错误。如果 P 不为 static,则实例表达式为 this。
~P = value 用参数列表 (value) 调用包含类或结构中的属性 P 的 set 访问器。如果 P 是只读的,则发生编译时错误。如果 P 不为 static,则用 this 来表达对应的实例。
~T.P 调用类或结构 T 中属性 P 的 get 访问器。如果 P 不为 static,或者如果 P 是只写的,则发生编译时错误。
~T.P = value 用参数列表 (value) 调用类或结构 T 中的属性 P 的 set 访问器。如果 P 不为 static,或者如果 P 是只读的,则发生编译时错误。
~e.P 用实例表达式 e 调用由 e 的类型提供的类、结构或接口中属性 P 的 get 访问器。如果 P 为 static,或者如果 P 是只写的,则发生编译时错误。
~e.P = value 用实例表达式 e 和参数列表 (value) 调用 e 的类型给定的类、结构或接口中属性 P 的 set 访问器。如果 P 为 static,或者如果 P 是只读的,则发生编译时错误。
c.事件访问
~E += value 调用包含类或结构中的事件 E 的 add 访问器。如果 E 不是静态的,则用 this 来表达对应的实例。 ~E -= value 调用包含类或结构中事件 E 的 remove 访问器。如果 E 不是静态的,则用 this 来表达对应的实例。
~T.E += value 调用类或结构 T 中事件 E 的 add 访问器。如果 E 不是静态的,则发生编译时错误。
~T.E -= value 调用类或结构 T 中事件 E 的 remove 访问器。如果 E 不是静态的,则发生编译时错误。
~e.E += value 用实例表达式 e 调用由 e 的类型提供的类、结构或接口中事件 E 的 add 访问器。如果 E 是静态的,则发生编译时错误。
~e.E -= value 用实例表达式 e 调用由 e 的类型给定的类、结构或接口中事件 E 的 remove 访问器。如果 E 是静态的,则发生编译时错误。
d.索引器访问
~e[x, y] 应用重载决策以在 e 的类型给定的类、结构或接口中选择最佳的索引器。用实例表达式 e 和参数列表 (x, y) 调用该索引器的 get 访问器。如果索引器是只写的,则发生编译时错误。
~e[x, y] = value 应用重载决策以在 e 的类型给定的类、结构或接口中选择最佳的索引器。用实例表达式 e 和参数列表 (x, y, value) 调用该索引器的 set 访问器。如果索引器是只读的,则发生编译时错误。
e.运算符调用
~-x 应用重载决策以在 x 的类型给定的类或结构中选择最佳的一元运算符。用参数列表 (x) 调用选定的运算符。
~x + y 应用重载决策以在 x 和 y 的类型给定的类或结构中选择最佳的二元运算符。使用参数列表 (x, y) 调用选定的运算符。
f.实例构造函数
~new T(x, y) 应用重载决策以在类或结构 T 中选择最佳的实例构造函数。用参数列表 (x, y) 调用该实例构造函数。
(2)自变量列表(argument lists)
a. 每个功能成员调用(fmi)包括一个自变量列表(argument list),该列表为功能成员的参数提供着实际值或变量引用;fmi的自变量列表的“固化”语法(syntax for specifying)是由功能成员的归类(category)决定的。
~对实例构建器、方法和委托,自变量是自变量列表;语法格式如下:
argument-list , argument
ref variable-reference
out variable-reference
~对属性,调用get访问器(accessor)时自变量列表清空(empty);调用set访问器时,由赋值操作符的右操作数标明的表达式组成自变量列表;
~对事件,由+=/-=操作符标明的右操作数的表达式组成自变量列表;
~对索引器,由索引器访问(access)中方括号之间标明的表达式构成自变量列表;调用set访问器时,赋值操作符的右操作数的表达式组成自变量列表;
~对用户自定义的操作符,一元操作符的单操作数或二元操作符的两个操作数构成自变量列表;
b.属性、事件、索引器和用户自定义的操作符的自变量(arguments)总是使用数值参数传递,功能成员的这些归类(category)不支持引用参数和输出参数;
c.自变量列表由逗号分开的一个或多个自变量组成;(每)自变量使用下列格式之一:
~表达式
~关键字ref后跟变量引用
~关键字out后跟变量引用
d.fmi在运行时段,自变量列表的表达式或变量引用按从左到右的顺序计算:
~对于数值参数,计算自变量表达式,执行到相应参数类型的隐式转换。结果值成为fmi中数值参数的初始值。
~对于引用参数或输出参数,作为计算变量引用结果的存储位置,成为fmi中的参数表示的存储位置。如果作为引用参数或输出参数给定的变量引用,是一个引用类型(reference-type)的数组元素,则执行一个运行时检查以确保该数组的元素类型与参数的类型相同。如果检查失败,则引发 System.ArrayTypeMismatchException
。
e.方法、索引器和实例构造函数可以将其最右边的参数声明为参数数组。是以正常形式(normal form)还是以扩展形式(expanded form)调用这类函数成员取决于哪种形式适用:
~当以正常形式调用带有参数数组的函数成员时,作为参数数组给定的自变量,必须是某个类型(a type)的单一(single)表达式,该类型隐式可转换为参数数组(parameter array type)的类型。在此情况下,参数数组的作用(act as)完全(precisely like)类似于数值参数。
~当以扩展形式调用带有参数数组的函数成员时,调用必须为参数数组(parameter array)指明零个或多个自变量,其中每个自变量都是某个类型(a type)的表达式,该类型隐式可转换为参数数组元素的类型(element type)。在此情况下,调用会创建一个(该)参数数组类型的实例,该实例的长度对应于自变量的个数,并用给定的自变量值初始化这个数组实例的每个元素,然后用新创建的数组实例作为实际参数(actual argument)。
注意:
~只要存在从B到A的隐式引用转换(implicit reference conversion),数组协差规则(co-variance rules)允许一个数组类型A[]的值成为另一个数组类型B[]的实例的引用(reference),所以,当把引用类型(reference type)的数组元素作为引用参数或输出参数传递时,必须执行运行时检查(run-time check),以确保该数组的实际元素类型与参数的类型完全一致(identical)。见下面的示例,
class Test { static void F(ref object x) {...} static void Main() { object[] a = new object[10]; object[] b = new string[10]; F(ref a[0]); // Ok F(ref b[1]); // ArrayTypeMismatchException } } //第二次函数调用发生错误!
~当以扩展形式调用带有参数数组的函数成员时,其调用处理过程完全类似于(as if)--带有数组初始值设定项(array initializer)的一个数组创建表达式(array creation expression)--被插入到扩展参数处(inserted around)。
//声明如下的函数 void F(int x, int y, params object[] args); //执行函数调用 F(10, 20); F(10, 20, 30, 40); F(10, 20, 1, "hello", 3.0); //等效于.. F(10, 20, new object[] {}); //为参数数组给定零个参数时,会创建空数组 F(10, 20, new object[] {30, 40}); F(10, 20, new object[] {1, "hello", 3.0});
(3)重载方案/策略(overload resolution)
a.重载方案是在编译时,一旦给出参数列表和一整套候选函数成员(candidate)供选择时,便能够挑出最
恰当的函数成员来调用的机制。在c#中,它主要用于以下函数调用(invocation)语境(context)中:
~调用表达式中(invocation-expression)用到的(named)方法调用;
~对象创建表达式中用到的实例构建器调用;
~通过元素访问形式(element-access)用到的索引访问器(indexer accessor)调用;
~表达式内用到的(referenced)预定义或自定义操作符.
以上每个"环境"都以自己的唯一方式来定义候选函数成员和参数列表的(list of arguments)集合。例如,"调用方 法"(method invocation)不包括标记为override的方法,另外一种情况,如果派生类中方法可用(is applicable),那么基类中的方法就不作为"侯选"(not candidate)。
一旦标定出候选的函数成员和参数列表,选择最佳函数成员(best function member)是按照以下规则进行:
•如果给定了适用的候选函数成员集,则在其中选出最佳函数成员。
•如果该集合只包含一个函数成员,则该函数成员为最佳函数成员。
•否则,最佳函数成员的选择依据是:各成员对给定的参数列表的匹配程度。比所有其他函数成员匹配得更好的那个函数成员就是最佳函数成员,但有一个前提:必须使用 第 7.4.2.2 节 中的规则将每个函数成员与所有其他函数成员进行比较。
•如果不是正好有一个函数成员比所有其他函数成员都好,则函数成员调用不明确(ambiguous)并发生编译时错误。
b.适用的函数成员
当函数成员满足下列所有条件时,就称它是对(with respect to)参数列表A--可应用的(applicable)。
~A的参数数目与函数成员声明的参数数目相同。
~对A的每个参数,自变量的参数传递模式(passing mode of the argument)--包括值、ref 或 out,与相应参数的参数(parameter)传递模式相同,而且
~~对值参数或参数数组,存在从自变量类型到相应参数的类型的隐式转换,或
~~对于 ref 或 out 参数,自变量的类型( type of the argument )与相应参数的(parameter)类型相同。ref 或 out 参数毕竟(After all)只是传递的自变量的别名(alias)。
包含参数数组的函数成员,如果按照上述规则是可应用的,则把它称作按常规形式适用(applicable in its normal form),反之,它可能是以扩展形式适用(applicable in its expanded form)。
~如果 A 中的自变量比函数成员声明中的固定参数的数目少,则该函数成员的展开形式无法构造(这是因为构造扩展形式的方法是:用参数数组的元素类型的零个或多个值参数,替换函数成员声明中的参数数组,使参数列表 A 中的参数数目匹配总的参数数目。),且该该函数成员不适用。
~如果在声明函数成员的类、结构或接口中,已经包含另一个与扩展形式具有相同签名的适用函数成员,则不适用扩展形式。
~除此以外,如果对于 A 中的每个自变量,它的参数传递模式与相应参数的参数传递模式相同,并且下列条件成立,则称该成员函数以展开形式适用:
~~对于固定值参数或展开操作所创建的值参数,存在从自变量的类型到相应参数的类型的隐式转换,或者
~~对于 ref 或 out 参数,参数的类型与相应参数的类型相同。
c.更好的函数成员
给定一个带有参数类型集 {A1, A2, ..., AN} 的参数列表 A 和带有参数类型 {P1, P2, ..., PN} 和 {Q1, Q2, ..., QN} 的两个可应用的函数成员 MP 和 MQ,则在以下情况中,MP 定义为比 MQ 更好的函数成员:
~对于每个参数,从 AX 到 PX 的隐式转换都不比从 AX 到 QX 的隐式转换差(not worse),并且
~对于至少一个参数,从 AX 到 PX 的转换比从 AX 到 QX 的转换更好(better)。
当执行此计算时,如果 MP 或 MQ 以扩展形式适用,则 PX 或 QX 所代表的是扩展形式的参数列表中的参数。
d.更好的转换
假设有一个从类型 S 转换到类型 T1 的隐式转换 C1,和一个从类型 S 转换到类型 T2 的隐式转换 C2,将按下列规则确定这两个转换中哪个是更好的转换:
~如果 T1 和 T2 是相同类型,则两个转换都不是更好的转换。
~如果 S 为 T1,则 C1 为更好的转换。
~如果 S 为 T2,则 C2 为更好的转换。
~如果存在从 T1 到 T2 的隐式转换,且不存在从 T2 到 T1 的隐式转换,则 C1 为更好的转换。
~如果存在从 T2 到 T1 的隐式转换,且不存在从 T1 到 T2 的隐式转换,则 C2 为更好的转换。
~如果 T1 为 sbyte 而 T2 为 byte、ushort、uint 或 ulong,则 C1 为更好的转换。
~如果 T2 为 sbyte 而 T1 为 byte、ushort、uint 或 ulong,则 C2 为更好的转换。
~如果 T1 为 short 而 T2 为 ushort、uint 或 ulong,则 C1 为更好的转换。
~如果 T2 为 short 而 T1 为 ushort、uint 或 ulong,则 C2 为更好的转换。
~如果 T1 为 int 而 T2 为 uint 或 ulong,则 C1 为更好的转换。
~如果 T2 为 int 而 T1 为 uint 或 ulong,则 C2 为更好的转换。
~如果 T1 为 long 而 T2 为 ulong,则 C1 为更好的转换。
~如果 T2 为 long 而 T1 为 ulong,则 C2 为更好的转换。
~否则,两个转换都不是更好的转换。
e.函数成员调用(function member invocation)
本段描述在运行时发生的调用一个特定的函数成员的进程。这里假定这个要调用的特定成员,已在编译时进程确定了(可能采用重载决策从一组候选函数成员中选出)。
为了描述调用进程,将函数成员分成两类:
静态函数成员。包括实例构造函数、静态方法、静态属性访问器和用户定义的操作符。静态函数成员总是非虚拟的。
实例函数成员。包括实例方法、实例属性访问器和索引器访问器。实例函数成员不是非虚拟的就是虚拟的,并且总是在特定的实例上调用。该实例由实例表达式计算,并且在函数成员内可以以 this (第 7.5.7 节)的形式对它进行访问。
函数成员调用的运行时处理包括以下步骤(其中 M 是函数成员,如果 M 是实例成员,则 E 是实例表达式):
1'如果 M 是静态函数成员,则:
~它的参数列表按照(2)中的说明进行计算。
~调用 M。
2'如果 M 是在值类型中声明的实例函数成员,则:
~计算 E。如果该计算导致异常,则不执行进一步的操作。
~如果 E 没有被归类为一个变量,则创建一个与 E 同类型的临时局部变量,并将 E 的值赋给该变量。这样,E 就被重新归类为对该临时局部变量的一个引用。该临时变量在 M 中可以以 this 的形式被访问,但不能以任何其他形式。因此,仅当 E 是真正的变量时,调用方才可能观察到 M 对 this 所做的更改。
~参数列表按照(2)中的说明进行计算。
~调用 M。E 引用的变量成为 this 引用的变量。
3'如果 M 是在引用类型中声明的实例函数成员,则:
~计算 E。如果该计算导致异常,则不执行进一步的操作。
~参数列表按照(2)中的说明进行计算。
~如果 E 的类型为值类型,则执行装箱转换以将 E 转换为 object 类型,并且在下列步骤中,E 被视为 object 类型。这种情况下,M 只能是 System.Object 的成员。
检查 E 的值是否有效。如果 E 的值为 null,则引发 System.NullReferenceException,并且不执行进一步的操作。
~要调用的函数成员实现按以下规则确定:
如果 E 的编译时类型是接口,则调用的函数成员是 M 的实现,此实现是由 E 引用的实例在运行时所属的类型提供的。确定此函数成员时,应用接口映射规则确定由 E 引用的实例运行时类型提供的 M 实现。否则,
~~如果 M 是虚函数成员,则调用的函数成员是由 E 引用的实例运行时类型提供的 M 实现。确定此函数成员时,应用“确定 M 的派生程度最大的实现”的规则(相对于 E 引用的实例的运行时类型)。 否则,
~~M 是非虚函数成员,调用的函数成员是 M 本身。
~调用在上一步中确定的函数成员实现。E 引用的对象成为 this 引用的对象。
小结:
本篇主要描述了函数成员的基本情况。从函数本身来讲,在普通的CLR环境下,必须通过编译来“喂”给机器去识别,这样的编译模式下,函数仍然无法在运行时动态化,这应该是DLR的用武之地。--运行时,识别环境(context),可配置地动态确定运行时的反应行为。
发表评论
-
ZT,一篇好文
2010-05-03 10:33 1001读读语言大牛们(其中有位是Anders)这篇文章,会很受益。( ... -
关于“匿名方法”与“lambda操作符”的实现
2010-03-24 22:29 872在<关于“回调”的实现>一文中,我们探讨了使用委托 ... -
effective hierarchy(二)之 函数合辑(2)
2009-09-16 21:29 727介绍: 本节我们来看看另外一种封装,构建件。构建件作为 ... -
effective hierarchy(二)之 函数合辑(1)
2009-08-19 14:53 781“暴露”阶段:值-> ... -
effective hierarchy(一)之 基本概念(8)
2009-07-02 23:39 686MSDN,C#2 一、语句 1.结束点和可达性(en ... -
effective hierarchy(一)之 基本概念(7)
2009-06-23 21:15 937以下可跳过: [立记保留:到现在为止,我满意的是认真的精神。 ... -
effective hierarchy(一)之 基本概念(6)
2009-06-21 00:34 951MSDN,C#2.0 转换(conversions) ... -
effective hierarchy(一)之 基本概念(5)
2009-06-18 22:16 717MSDN,C#2.0 变量基本点: 变量代表 ... -
effective hierarchy(一)之 基本概念(4)
2009-06-15 15:59 728MSDN,C#2.0: 一、名字空间和类型名称(nam ... -
effective hierarchy(一)之 基本概念(3)
2009-06-14 15:00 732MSDN,C#2.0: 一、签 ... -
effective hierarchy(一)之 基本概念(2)
2009-06-13 18:22 828MSDN:基本概念 一、 ... -
effective hierarchy(一) 之基本概念(1)
2009-06-11 09:37 780我告诫自己,不要忽略简单的东西,又要扎实。所以这一篇开始,专门 ... -
effective hierarchy(一)之 属性与索引器
2009-06-07 14:07 1152编程笺言:“优良的设计 ... -
effective hierarchy(一)之 从array说起(4)
2009-06-07 00:53 805回顾:上一节中,我们 ... -
effective hierarchy(一)之 从array说起(3)
2009-06-06 21:20 702回顾: 从上一节中,可以看出枚举的易用性对数组使用的启示意义 ... -
effective hierarchy(一)之 从array说起(2)
2009-06-06 09:34 691复习: 从上一节,可 ... -
effective hierarchy(一)之 从array说起(1)
2009-05-29 13:59 892MSDN(c#2.0): 数组的元义是 ... -
effective hierarchy(一)之 C#中的new
2009-05-27 23:21 841MSDN(c#2.0): 在msdn中,指出new的三种用法。 ...
相关推荐
在了解 IRQ hierarchy 的初始化及构建过程之前,需要先了解三个基本概念:IRQ、HWIRQ 和 GSI。 IRQ(Interrupt Request)是系统中的一种机制,允许外部设备请求 CPU 的注意,以便处理某些事件。IRQ 是一个抽象的...
本篇文档将详细介绍如何为员工及其部门经理创建一个层次数据源(Hierarchy Extractor)。通过这个层次数据源,管理者可以方便地获取到他们直接下属的信息以及这些下属所负责或有权访问的数据。此文档适用于运行ECC 5.0...
Android 开发中,UI 分析工具 Hierarchy Viewer 是一个非常有用的工具,可以帮助开发者快速、方便地设计、调试和调整界面,提高用户的开发效率。本文将详细介绍如何使用 Hierarchy Viewer 工具在 Android 开发过程中...
Hierarchy PRO是一个高级的Hierarchy面板扩展,它提供了更多的自定义选项和便捷的功能。此插件可能包括但不限于以下特性: 1. **过滤与排序**:Hierarchy PRO允许用户根据需求筛选和排序场景中的游戏对象,比如按...
解决这个启动 View Hierarchy时的这个bug: hierarchy viewer unable to debug device
Hierarchy Viewer是Android SDK中自带的一款强大的UI设计与检测工具。它位于Android SDK的`tools`目录下,文件名为`hierarchyviewer.bat`。对于Android开发者来说,这是一个不可或缺的工具,能够帮助他们在开发过程...
效果及使用方法:https://blog.csdn.net/qq_26318597/article/details/131373576 1.导入插件包 2.选中Hierarchy中的物体 3.右键选择“复制Hierarchy路径” 4.Ctrl + V 粘贴
#### 一、Hierarchy Viewer概览 Hierarchy Viewer是一款由Google提供的强大工具,专为Android开发者设计,旨在辅助界面设计、调试及优化工作流程。通过直观地展示应用UI的层级结构,它使得开发者能够轻松识别布局...
Unity是世界上最流行的游戏开发引擎之一,它为开发者提供了丰富的工具集来创建交互式3D和2D内容。在Unity中,Hierarchy面板是一个至关重要的组成部分,它显示了场景中的所有游戏对象及其层次结构。QHierarchy是一款...
Enhanced_Hierarchy_2.0_v2.4.5.unitypackage 最新版本哦 正版
Hierarchy PRO 2021 v2021.1u9
Unity是世界上最受欢迎的游戏开发引擎之一,它提供了丰富的工具和功能,让开发者能够创建高质量的2D和3D游戏。在Unity中,"层级编辑器"(Hierarchy)是至关重要的一个部分,它允许开发者组织和管理场景中的游戏对象...
在游戏开发领域,“演化你的游戏实体层级”(Evolve Your Hierarchy)这一概念强调了从传统的深度类层级结构向更灵活、可扩展的游戏实体组件化方法转变的重要性。这种方法不仅提高了代码的复用性与可维护性,还简化...
WPF Class Hierarchy
Hierarchy2 v1.3.10.0
通过阅读和理解《VS2010 MFC Hierarchy Chart》的三个部分(MFC_Hierarchy_Chart1of3.pdf、MFC_Hierarchy_Chart2of3.pdf、MFC_Hierarchy_Chart3of3.pdf),开发者可以深入理解MFC的内部结构,从而更好地利用MFC开发...
在这个名为“前端项目-d3-hierarchy.zip”的压缩包中,包含了一个使用D3.js库实现的层次数据可视化布局算法。D3.js(Data-Driven Documents)是一个强大的JavaScript库,专为创建动态、交互式的SVG、Canvas或WebGL...
网络列表可以包含基本元件、元件库中的模型以及用户定义的函数。 4. **元件库(Component Libraries)**:ADS提供丰富的内置元件库,包括模拟、数字和射频元件。设计师可以自定义库,创建专用的元件模型以满足特定...