C# 中这句函数怎么理解。public void Damage(int main voiddamageCount)

& & & &这是一个横版射击游戏。 教程来自:
& 中文版教程:
教程文章已经详细地介绍实现过程,这里就不再复述,只做一些简单的笔记记录,以供备忘。
1.创建第一个场景
新建工程。接着在&
Project&面板上创建如下文件夹:
Hierarchy&面板上创建多个空对象,形成以下结构:
这些空对象的
Position保持为(0, 0, 0)即可。保存场景,名称为&
2.添加显示背景
将背景图片放入&
Textures&文件夹,确认这张图片的纹理类型,即&
Texture Type&属性为& Sprite&,如下图所示:
在场景中添加一个Sprite游戏对象,设置其&
Sprite&属性为刚才导入的背景图片。重命名这个对象为&
Background1&,将其移动到&
Level -& 0 - Background&里面,设置其&
Position&为 (0, 0, 0)。接着添加背景元素。导入平台图片到 &
Textures&文件夹,选中&
platforms&图片,设置其&
Sprite Mode&为& Multiple&,然后点击&
Sprite Editor&,如下图所示:
Sprite Editor&窗口中,进行绘制每个平台的包围矩形,以便将纹理分割成更小的部分。然后分别命名为&
platform1&和&
platform2&,如下图所示:
创建一个新的 Sprite游戏对象,设置其&
Sprite&属性为& platform1&。再在创建新 Sprite对象, 设置其&
Sprite&属性为& platform2&。将它们放置到&
1 - Middleground&对象里,并且确认它们的Z坐标为0。将这两个对象从&
Hierarchy&面板拖动到&
Project&面板下的&
Prefabs&文件夹,保存成预制对象。接着,为了避免显示顺序问题,修改下游戏对象的Z坐标,如下所示:
Z Position
0 - Background
1 - Middleground
2 - Foreground
此时,点击&
Scene&面板上的2D到3D视图切换,可以清楚看到层次:
3.创建主角和敌人
导入主角图片 到 &
Textures&文件夹,创建一个Sprite游戏对象,命名为&
Player&, 设置其&
Sprite&属性为刚才导入的主角图片。将此对象放入&
2 - Foreground&层里,设置其
Scale为 (0.2, 0.2, 1)。接着,为主角添加盒碰撞体组件,点击&
Add Component&按钮,选择&
Box Collider 2D&,设置其
Size为 (10, 10),虽然这还是大于实际的区域,但已比图片小多了,如下图所示:
(可以通过按住Shift键,来调整绿色碰撞范围)
接着,再为主角对象添加&
Rigidbody 2D&刚体组件,现在运行可以看到如下结果:
可以看到主角往下落了,这是因为刚体带有重力,但在这个游戏不需要用到,将&
Gravity Scale&属性设为0即可。另外,不想因为物理而引起的主角旋转,则将&
Fixed Angles&属性勾选上。完整的设置如下图所示:
开始准备让主角移动。在&
Scripts&文件夹里,创建一个C#脚本,名称为&
PlayerScript&,实现让方向键移动主角,代码如下:
using&UnityE
///&&summary&
///&Player&controller&and&behavior
///&&/summary&
public& class&PlayerScript&:&MonoBehaviour
&& ///&&summary&
&& ///&1&-&The&speed&of&the&ship
&& ///&&/summary&
&& public&Vector2&speed&=& new&Vector2( 50,& 50);
&& //&2&-&Store&the&movement
&& private&Vector2&
&& void&Update()
&&&& //&3&-&Retrieve&axis&information
&&&& float&inputX&=&Input.GetAxis( &Horizontal&);
&&&& float&inputY&=&Input.GetAxis( &Vertical&);
&&&& //&4&-&Movement&per&direction
&&&&movement&=& new&Vector2(
&&&&&&speed.x&*&inputX,
&&&&&&speed.y&*&inputY);
&& void&FixedUpdate()
&&&& //&5&-&Move&the&game&object
&&&&rigidbody2D.velocity&=&
这里以改变刚体的速率来达到主角的移动,而不是通过直接改变&transform.Translate&,因为那样的话,可能会不产生碰撞。将此脚本附加到主角对象上,现在运行,方向键来控制移动,如下图所示:
接下来,添加第一个敌人。导入章鱼敌人图片到 &
Textures&文件夹,创建一个Sprite游戏对象,命名为&
Poulpi &, 设置其&
Sprite&属性为刚才导入的图片,设置&
Scale&属性为(0.4, 0.4, 1),添加&
Box Collider 2D&组件,其
Size为(4, 4),添加&
Rigidbody 2D&组件,其&
Gravity Scale&属性为0,并且勾选&
Fixed Angles&属性框。将对象保存为预制。在这里只让章鱼简单地往前行,创建一个脚本,命名为&
MoveScript&,代码如下:
using&UnityE
///&&summary&
///&Simply&moves&the&current&game&object
///&&/summary&
public& class&MoveScript&:&MonoBehaviour
&& //&1&-&Designer&variables
&& ///&&summary&
&& ///&Object&speed
&& ///&&/summary&
&& public&Vector2&speed&=& new&Vector2( 10,& 10);
&& ///&&summary&
&& ///&Moving&direction
&& ///&&/summary&
&& public&Vector2&direction&=& new&Vector2(- 1,& 0);
&& private&Vector2&
&& void&Update()
&&&& //&2&-&Movement
&&&&movement&=& new&Vector2(
&&&&&&speed.x&*&direction.x,
&&&&&&speed.y&*&direction.y);
&& void&FixedUpdate()
&&&& //&Apply&movement&to&the&rigidbody
&&&&rigidbody2D.velocity&=&
将此脚本附加到章鱼对象上,现在运行,可以看到章鱼往前移动,如下图所示:
此时如果将主角放在章鱼前面,两个对象将会产生碰撞,互相阻塞对方的移动。
导入子弹图片 到 &
Textures&文件夹,创建一个Sprite游戏对象,命名为&
PlayerShot &, 设置其&
Sprite&属性为刚才导入的图片 ,设置&
Scale&属性为(0.75, 0.75, 1) ,添加&
Rigidbody 2D&组件,其&
Gravity Scale&属性为0,并且勾选&
Fixed Angles&属性框 ,添加&
Box Collider 2D&组件,其
Size为(1, 1),并且勾选&
IsTrigger&属性 。勾选&
IsTrigger&属性表示该碰撞体用于触发事件,并将被物理引擎所忽略。意味着,子弹将穿过触碰到的对象,而不会阻碍对象的移动,触碰的时候将会引发&
OnTriggerEnter2D&事件。创建一个脚本,命名为&
ShotScript&,代码如下:
using&UnityE
///&&summary&
///&Projectile&behavior
///&&/summary&
public& class&ShotScript&:&MonoBehaviour
&& //&1&-&Designer&variables
&& ///&&summary&
&& ///&Damage&inflicted
&& ///&&/summary&
&& public& int&damage&=& 1;
&& ///&&summary&
&& ///&Projectile&damage&player&or&enemies?
&& ///&&/summary&
&& public& bool&isEnemyShot&=&
&& void&Start()
&&&& //&2&-&Limited&time&to&live&to&avoid&any&leak
&&&&Destroy(gameObject,& 20);& //&20sec
将此脚本附加到子弹对象上,然后将&
MoveScript&脚本也附加到子弹对象上以便可以移动。保存此对象为预制。接着,让碰撞产生伤害效果。创建一个脚本,命名为&
HealthScript&,代码如下:
using&UnityE
///&&summary&
///&Handle&hitpoints&and&damages
///&&/summary&
public& class&HealthScript&:&MonoBehaviour
&& ///&&summary&
&& ///&Total&hitpoints
&& ///&&/summary&
&& public& int&hp&=& 1;
&& ///&&summary&
&& ///&Enemy&or&player?
&& ///&&/summary&
&& public& bool&isEnemy&=&
&& ///&&summary&
&& ///&Inflicts&damage&and&check&if&the&object&should&be&destroyed
&& ///&&/summary&
&& ///&&param&name=&damageCount&&&/param&
&& public& void&Damage( int&damageCount)
&&&&hp&-=&damageC
&&&& if&(hp&&=& 0)
&&&&&& //&Dead!
&&&&&&Destroy(gameObject);
&& void&OnTriggerEnter2D(Collider2D&otherCollider)
&&&& //&Is&this&a&shot?
&&&&ShotScript&shot&=&otherCollider.gameObject.GetComponent&ShotScript&();
&&&& if&(shot&!=& null)
&&&&&& //&Avoid&friendly&fire
&&&&&& if&(shot.isEnemyShot&!=&isEnemy)
&&&&&&&&Damage(shot.damage);
&&&&&&&& //&Destroy&the&shot
&&&&&&&&Destroy(shot.gameObject);& //&Remember&to&always&target&the&game&object,&otherwise&you&will&just&remove&the&script
将此脚本附加到
Poulpi预制体上。现在运行,让子弹和章鱼碰撞,可以看到如下结果:
如果章鱼的生命值大于子弹的伤害值,那么章鱼就不会被消灭,可以试着通过改变章鱼对象的&
HealthScript&的hp值。接着,准备可以射击。创建一个脚本,命名为&
WeaponScript&,代码如下:
using&UnityE
///&&summary&
///&Launch&projectile
///&&/summary&
public& class&WeaponScript&:&MonoBehaviour
&& //--------------------------------
&& //&1&-&Designer&variables
&& //--------------------------------
&& ///&&summary&
&& ///&Projectile&prefab&for&shooting
&& ///&&/summary&
&& public&Transform&shotP
&& ///&&summary&
&& ///&Cooldown&in&seconds&between&two&shots
&& ///&&/summary&
&& public& float&shootingRate&=& 0.25f;
&& //--------------------------------
&& //&2&-&Cooldown
&& //--------------------------------
&& private& float&shootC
&& void&Start()
&&&&shootCooldown&=&0f;
&& void&Update()
&&&& if&(shootCooldown&&& 0)
&&&&&&shootCooldown&-=&Time.deltaT
&& //--------------------------------
&& //&3&-&Shooting&from&another&script
&& //--------------------------------
&& ///&&summary&
&& ///&Create&a&new&projectile&if&possible
&& ///&&/summary&
&& public& void&Attack( bool&isEnemy)
&&&& if&(CanAttack)
&&&&&&shootCooldown&=&shootingR
&&&&&& //&Create&a&new&shot
&&&&&&var&shotTransform&=&Instantiate(shotPrefab)& as&T
&&&&&& //&Assign&position
&&&&&&shotTransform.position&=&transform.
&&&&&& //&The&is&enemy&property
&&&&&&ShotScript&shot&=&shotTransform.gameObject.GetComponent&ShotScript&();
&&&&&& if&(shot&!=& null)
&&&&&&&&shot.isEnemyShot&=&isE
&&&&&& //&Make&the&weapon&shot&always&towards&it
&&&&&&MoveScript&move&=&shotTransform.gameObject.GetComponent&MoveScript&();
&&&&&& if&(move&!=& null)
&&&&&&&&move.direction&=& this.transform.& //&towards&in&2D&space&is&the&right&of&the&sprite
&& ///&&summary&
&& ///&Is&the&weapon&ready&to&create&a&new&projectile?
&& ///&&/summary&
&& public& bool&CanAttack
&&&&&& return&shootCooldown&&=&0f;
将这个脚本附加到主角对象上,设置其&
Shot Prefab&属性为&
PlayerShot&预制体。打开&
PlayerScript&脚本,在
Update()方法里面,加入以下片段:
void&Update()
&&&& //&...
&&&& //&5&-&Shooting
&&&& bool&shoot&=&Input.GetButtonDown( &Fire1&);
&&&&shoot&|=&Input.GetButtonDown( &Fire2&);
&&&& //&Careful:&For&Mac&users,&ctrl&+&arrow&is&a&bad&idea
&&&& if&(shoot)
&&&&&&WeaponScript&weapon&=&GetComponent&WeaponScript&();
&&&&&& if&(weapon&!=& null)
&&&&&&&& //&false&because&the&player&is&not&an&enemy
&&&&&&&&weapon.Attack( false);
&&&& //&...
当收到射击的按钮状态,调用
Attack(false)方法。现在运行,可以看到如下结果:
接下来,准备创建敌人的子弹。 导入敌人子弹图片 到 &
Textures&文件夹, 选中&
PlayerShot&预制体,按下
Ctrl+D进行复制,命名为&
EnemyShot1&,然后改变其
Sprite为刚才导入的图片,设置其
Scale为 (0.35, 0.35, 1)。接着,让章鱼可以射击。将&
WeaponScript&脚本附加到章鱼对象上,拖动&
EnemyShot1&预制体到其&
Shot Prefab&属性,创建一个脚本,命名为&
EnemyScript&,用来简单地每一帧进行自动射击,代码如下:
using&UnityE
///&&summary&
///&Enemy&generic&behavior
///&&/summary&
public& class&EnemyScript&:&MonoBehaviour
&& private&WeaponScript&
&& void&Awake()
&&&& //&Retrieve&the&weapon&only&once
&&&&weapon&=&GetComponent&WeaponScript&();
&& void&Update()
&&&& //&Auto-fire
&&&& if&(weapon&!=& null&&&&weapon.CanAttack)
&&&&&&weapon.Attack( true);
将此脚本附加到章鱼对象上,如下图所示:
现在运行,可以看到如下结果:
可以看到章鱼向右射击了子弹,这是因为代码就是让它那么做的。实际上,应该做到可以朝向任何方向射击子弹。在这里,创建一个空对象,命名为&
WeaponObject&,删除章鱼预制体身上的&
WeaponScript&脚本,将&
WeaponScript&脚本附加到&
WeaponObject&对象上,并且 拖动&
EnemyShot1&预制体到其&
Shot Prefab&属性,设置&
WeaponObject&对象的&
Rotation&属性为(0, 0, 180),然后保存为预制,如下所示:
接着,修改&
EnemyScript&,代码为如下:
using&System.Collections.G
using&UnityE
///&&summary&
///&Enemy&generic&behavior
///&&/summary&
public& class&EnemyScript&:&MonoBehaviour
&& private&WeaponScript[]&
&& void&Awake()
&&&& //&Retrieve&the&weapon&only&once
&&&&weapons&=&GetComponentsInChildren&WeaponScript&();
&& void&Update()
&&&& foreach&(WeaponScript&weapon& in&weapons)
&&&&&& //&Auto-fire
&&&&&& if&(weapon&!=& null&&&&weapon.CanAttack)
&&&&&&&&weapon.Attack( true);
可以适当调整子弹的移动速度,它应该快于章鱼的移动速度。现在运行,如下图所示:
按这种方式,可以轻易实现多个方向的射击。复制添加一个&
WeaponObject&对象,让这两个&
WeaponObject&对象的旋转不同即可。现在主角被章鱼攻击到,但是没有任何伤害。将&
HealthScript&脚本附加到主角对象上,确保&
Is&Enemy&属性不被勾选。现在运行,可以看到如下结果:
目前,当主角和章鱼碰撞时,仅仅只是阻碍对方的移动而已,在这里改成互相受到伤害。打开&
PlayerScript&文件,添加如下代码:
//PlayerScript.cs
void&OnCollisionEnter2D(Collision2D&collision)
&&&& bool&damagePlayer&=&
&&&& //&Collision&with&enemy
&&&&EnemyScript&enemy&=&collision.gameObject.GetComponent&EnemyScript&();
&&&& if&(enemy&!=& null)
&&&&&& //&Kill&the&enemy
&&&&&&HealthScript&enemyHealth&=&enemy.GetComponent&HealthScript&();
&&&&&& if&(enemyHealth&!=& null)&enemyHealth.Damage(enemyHealth.hp);
&&&&&&damagePlayer&=&
&&&& //&Damage&the&player
&&&& if&(damagePlayer)
&&&&&&HealthScript&playerHealth&=& this.GetComponent&HealthScript&();
&&&&&& if&(playerHealth&!=& null)&playerHealth.Damage( 1);
至此,一个基本的射击游戏完成。下一篇,将进行增强表现,完善游戏。C#中值类型参数与引用类型参数的区别!??如 Public static void AddOne(ref int a) { a++ }_百度知道
C#中值类型参数与引用类型参数的区别!??如 Public static void AddOne(ref int a) { a++ }
必须用引用才可以REF表示将参数作为引用类型传入所以即使它是值类型(比如INT型)值类型 传递给函数是一个具体指引用类型 传递给函数的是一个地址如果想在函数中改变外面的值;则a的值为9.如果是AddOne(a);AddOne(ref a),函数中的变化会作用到其本身比如int a=8,也视作引用
其他类似问题
按默认排序
其他3条回答
但是运行后发现仍然是a=5,ref int b){
int s,你会发现;}如果使用exchange(a;public void exchage(int a,int b){
b=s。 方法内发生的对参数的更改对该变量中存储的原始数据无任何影响;
s=a,按照设想应该是 a=10,后者包含对其数据的引用;
a=b,必须使用 ref 或 out 关键字通过引用传递该参数eg,ref b)后;}调用exchange(ref a。 因此,这与引用类型变量不同。 如果希望所调用的方法更改参数的值,b=10,b=10 这样的值类型参数就是不改变值的如果使用下边的public void exchage(
b=s,向方法传递值类型变量意味着向方法传递变量的一个副本,b)以后;int s=0:经典的交换算法int a=5值类型变量直接包含其数据
值类型参数,以Public static void AddOne( int a) { a++ }为例,此处的a就是值类型参数,如果调用此方法时传给a的值为5,在执行此方法过程中,虽然自加了一次,但是在方法外部,a还是5,不会变;但a若是ref引用类型则不然,执行完方法调用后a就变成6了。eg:
static void Main(string[] args)
Console.WriteLine(&a=&+a);
AddOne(a);
Console.WriteLine(&a作为值参数传递给方法后a=&+a);
Console.WriteLine(&a=& + a);
AddOne(ref a);
Console.WriteLine(&a作为ref引用参数传递给方法后a=& + a);
Console.ReadKey();
public static void AddOne(int a)
Console.WriteLine(&方法内的a=&+a);
public static void AddOne(ref int a)
Console.WriteLine(&方法内的a=& + a);
}输出结果为:a=5;方法内的a=6;a作为值参数传递给方法后a=5;a=5;方法内的a=6;a作为ref引用参数传递给方法后a=6;
ref的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁6731人阅读
public&void&Show()
&&&&&&&&&&&&Console.WriteLine("Nothing");
&&&&&&&&public&void&Show(int&number)
&&&&&&&&&&&&Console.WriteLine(number);
对于上面的代码,(1)没有参数,(2)使用了一个int类型的参数,(1)和(2)之间就构成了重载。(2)与(3)相比仅仅返回值不同,虽然重载不关心返回值的不同,但是在C#中不允许存在方法名和参数列表相同、返回值不同的方法,所以(2)和(3)不能同时存在于代码中,(3)如果不注释掉上面的代码是没有办法通过编译的。
上面我们仅仅讨论了重载的一些基本常识,下面我们探讨一下一些情况稍微复杂的重载情况。
首先我们看第一个版本:
using&System.Collections.G
using&System.T
namespace&OverrideDemo
&&&&class&Program
&&&&&&&&static&void&Main(string[]&args)
&&&&&&&&&&&&String&s&=&null;
&&&&&&&&&&&&Show(s);
&&&&&&&&&&&&Object&o&=&"123";
&&&&&&&&&&&&Show(o);
&&&&&&&&static&void&Show(string&s)
&&&&&&&&&&&&Console.WriteLine("String");
&&&&&&&&static&void&Show(Object&o)
&&&&&&&&&&&&Console.WriteLine("Object");
大家猜猜这个程序的运行结果是什么?以下是程序运行结果:StringObject
对以上代码进行分析,我们发现Show()方法有两种形式,一种是string类型的参数,一种是object类型参数,在一个类中存在方法名相同、参数列表不同(参数个数或者参数类型不同)的现象我们称之为overloading,即重载。不过这里的Show()方法的参数比较特殊,因为string类继承于Object类,也就是Show()方法的参数存在一种继承关系。从结果我们可以得出两点结论:(1)从String s =Show(s);最后调用的是static void Show(string s)这个方法我们可以得出,C#中方法调用是精确匹配的,也就是s是string类型,虽然string类型继承自object类型,尽管static void Show(Object o)也满足条件,但是方法声明中static void Show(string s)这个声明与s类型的最接近(因为s是string类型,与它最接近),所以执行static void Show(string s),而不执行static void Show(Object o)这个方法。(2)从Object o = "123"; Show(o);最后调用的是static void Show(Object o)这个方法我们可以得出,C#中如果存在方法重载,会根据其refrence type(引用类型)来调用对象的方法,而不是根据instance type(实例类型)来调用。尽管”123”是string类型,但是它的refrence type是object类型的,所以会调用static void Show(Object o)这个方法而不是static void Show(string s)。上面的Main()方法的IL代码如下:
.method private hidebysig static void& Main(string[] args) cil managed{& .entrypoint& // 代码大小&&&&&& 24 (0x18)& .maxstack& 1& .locals init ([0] string s,&&&&&&&&&& [1] object o)& IL_0000:& nop& IL_0001:& ldnull& IL_0002:& stloc.0& IL_0003:& ldloc.0& IL_0004:& call&&&&&& void OverrideDemo.Program::Show(string)& IL_0009:& nop& IL_000a:& ldstr&&&&& "123"& IL_000f:& stloc.1& IL_0010:& ldloc.1& IL_0011:& call&&&&&& void OverrideDemo.Program::Show(object)& IL_0016:& nop& IL_0017:& ret} // end of method Program::Main
从上面的IL代码我们可以看出对于string s=这句代码在IL中表示为:ldnull。
再根据上面的结论,我们看下面的代码:
public&class&Program
{&&&public&static&void&Main()
&&&&Show(null);
&&&&Show("");
&&&&Show(1);
&&&&static&void&Show(Object&o)
&&&&Console.WriteLine("Object");
&&&&static&void&Show(String&s)
&&&&Console.WriteLine("String");
猜猜上面的代码执行结果会是怎样的?以下是程序运行结果:StringString(感谢btbtshu、windman0925提醒此处的笔误,原来粘贴错了,成了Object了,现在已更正)Object
从上面的运行结果我们可以得出以下结论:(1)从Show(null)最后调用的是static void Show(String s)方法我们更进一步可以说在C#中是方法调用尽量精确匹配的。尽管null我们可以理解为一个空object对象或者一个空字符串,但是在这里C#还是精确为派生类。这就像我们没有钱,可以说没有一分钱也可以说没有500英镑,但是没有一分钱自然就没有500亿英镑,所以我们跟别人说没有钱的时候没有必要说没有500亿英镑一样。在这里自然null就表示空字符串。所以Show(null)这个方法会调用static void Show(String s)这个方法。这有点像下面的情况:一次活动大会上,主持人说:“身高不到1.60m的请坐在1到3排,身高不到1.75m的请做到4到6排,其他的请随便坐。”上面的语句似乎有些逻辑方面的问题,应该说身高超过1.60m但是不到1.75m的请坐到4到6排。但是如果你面对着一群拿着枪的强盗,他说上面的话时,恰好你也在场并且你的身高是1.55m,你会坐到哪一排?你总不可能冒着挨一枪的危险去纠正他的逻辑错误吧?最好的办法是坐到1到3排。因为无论怎么说你的身高是绝对满足不到1.60m这个条件的(尽管你的身高也满足强盗说的第二个条件,即身高不到1.75米,但是你肯定不会冒这个危险,从上下句的意思我们也能推断出人家的意思就是身高在1.61m到1.74m之间的人坐4到6排)。在上面的代码中,你在运行环境的眼中就是一个持枪的强盗,虽然null可以理解为null类型的string或者null类型的object,但是它不能向你问清楚这个到底是null类型的string或者null类型的object,因为string是Object的派生类,所以它按照null类型的string来调用相应的方法了。(2)从Show("")最后调用static void Show(String s)这个方法进一步证明了方法调用是尽量选择参数最匹配的那个执行。因为Show("")相当于:string s = ""; Show(s);s的引用类型是string,所以会调用static void Show(String s)这个方法。我们在这里可以假设一下:假如存在一个类A是String类的派生类(实际上string类是sealed的,也就是不可继承的,所以我说了是假设),并且存在在上面的代码改变如下:
public&class&Program
{&&&public&static&void&Main()
&&&&Show(null);
&&&&Show("");
&&&&static&void&Show(Object&o)
&&&&Console.WriteLine("Object");
&&&&static&void&Show(String&s)
&&&&Console.WriteLine("String");
&&&&static&void&Show(A&a)
&&&&Console.WriteLine("A");
如果上面的假设成立,上面的代码运行结果应该如下:AString
(3)为什么Show(1)会调用static void Show(Object o)这个方法呢?在这个类中与Show(1)最精确的方法重载应该是static void Show(int i)这种方法声明,但是方法中没有,因为int是继承自ValueType类,所以如果没有static void Show(int i)这种声明,那么其次接近的声明应该是static void Show(ValueType v)这种声明,可惜方法中依然没有,不过ValueType类继承自Object类,所以比static void Show(ValueType v)还次一点的方法重载声明应该是static void Show(Object o),而类中也确实存在这种声明,所以会调用static void Show(Object o)这个方法。当然从int到Object这个过程中存在一次box,也就是装箱(装箱是从值类型到引用类型的转换),这个可以从下面的IL代码可以看出来。
以下是第二种情况下Main()方法的IL代码:.method private hidebysig static void& Main(string[] args) cil managed{& .entrypoint& // 代码大小&&&&&& 32 (0x20)& .maxstack& 8& IL_0000:& nop& IL_0001:& ldnull& IL_0002:& call&&&&&& void OverrideDemo.Program::Show(string)& IL_0007:& nop& IL_0008:& ldstr&&&&& ""& IL_000d:& call&&&&&& void OverrideDemo.Program::Show(string)& IL_0012:& nop& IL_0013:& ldc.i4.1& IL_0014:& box&&&&&&& [mscorlib]System.Int32& IL_0019:& call&&&&&& void OverrideDemo.Program::Show(object)& IL_001e:& nop& IL_001f:& ret} // end of method Program::Main
下面我们对第二种情况的代码做一些变化,代码如下:
using&System.Collections.G
using&System.T
namespace&OverrideDemo
&&&&class&Program
&&&&&&&&static&void&Main(string[]&args)
&&&&&&&&&&&&Show(null);
&&&&&&&&&&&&Show("");&
&&&&&&&&&&&&Show(1);
&&&&&&&&static&void&Show(string&s)
&&&&&&&&&&&&Console.WriteLine("String");
&&&&&&&&static&void&Show(Object&o)
&&&&&&&&&&&&Console.WriteLine("Object");
&&&&&&&&static&void&Show(Program&p)
&&&&&&&&&&&&Console.WriteLine("Program");
上面的代码的运行结果是什么,你能猜出来吗?哈哈,上面的程序代码是没有运行结果的,因为它没有办法编译!编译情况如下:&为什么不能通过编译呢?原因就出在Show(null)这个方法这里!如果仅仅有static void Show(string s)和static void Show(Object o)方法构成重载关系,那么null我们既可以理解为空string引用也可以理解为空Object引用,因为string类型的限制更精确一些,所以C#会按照最精确地匹配成string类型,因而会执行static void Show(string s)这个方法。这是在前面的代码中已经被证明的。可是现在多了一个static void Show(Program p)方法的重载,null既可以理解成空string类型引用,也可以理解成空Program类型引用,因为string类和Program类都是Object类的派生类,所以按照前面的推论自然不会当成空Object类型的引用。因为String类和Program类之间不存在继承关系,按照最精确匹配原则,编译器无法决定匹配成String类还是Program类最精确,所以编译无法通过。
附注:最近尝试将一些比较基础的理论的知识用比较浅显的话语表达出来,主要是为了方便初学者理解和学习,也许某些词语用得不够professional,,但是如果词语太professional了怕初学者理解起来有困难,敬请各位大侠谅解,因为本文不是为你们写的。同时也欢迎各位与我交流经验和心得。最近垃圾邮件太多,所以不便在这里公开我的email,如果各位有兴趣与我交流,请加我为csdn好友,这样就能看见我的QQ和email了.
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:2486326次
积分:25987
积分:25987
排名:第84名
原创:248篇
转载:76篇
评论:6267条
(1)(1)(1)(3)(1)(3)(2)(1)(2)(1)(2)(3)(1)(1)(5)(3)(2)(2)(2)(4)(3)(4)(3)(7)(10)(3)(3)(3)(2)(2)(2)(2)(2)(4)(2)(3)(3)(2)(2)(5)(7)(5)(3)(3)(6)(2)(8)(10)(2)(23)(8)(13)(7)(7)(8)(9)(8)(13)(6)(15)(4)(18)(20)(13)(3)}

我要回帖

更多关于 void函数返回值 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信