C#方法解析
“方法”是包含一系列语句的代码块。 程序通过“调用”方法并指定所需的任何方法参数来执行语句。 在 C# 中,每个执行指令 都是在方法的上下文中执行的。
最近在写一个反射调用时,需要通过反射来调用方法。想写一个通用的方法调用的通用函数,这就需要将方法各种形式考虑在内。
在这里只是对C#4.0的方法进行一次简单总结,也希望给大家一个清晰的认识。
方法模板:可访问性 修饰符 返回值 方法名(参数列表){...}
可访问性: private protected internal public 方法修饰符: static abstract virtual / override 等 返回值: 某种类型或无返回值 方法名:methodname 参数列表:这个有多种情况 |
其实C#4.0中的方法,除了常见的方法,还有几种比较特殊的方法。
(1)属性,其实属性的 get 和 set 生成了两个单独方法<br> (2)索引,我们平时用的很多, this [ "code" ]等,其实在CLR中,也生成了get_Item 与set_Item两个方法。我们获取索引时,就可以用这个两个方法名 + 参数列表,获得相应的索引。<br> (3)泛型方法,如: T CreateInstance<T>(){...} |
但是这些都可以通过一定的 规律转为通常方法来处理。但在写反射的时候一定要分析到这类问题。
因为方法签名的其他部分比较简单,这里只是针对方法的参数列表进行展开讨论。
参数有多种:普通的也不赘述,如:void Do(string Msg){}; 这里只是讲述几种特殊的参数。
1、ref/out
如果不使用ref/out,则传递的只是这些值的Copy.传递的是引用类型的地址值,则将传递引用类型的地址值的一个Copy,实际上就是新开一
个不同的内存变量来存储这个地址值的拷贝。而是用ref/out,传递的还是引用类型的地址值,但是传递的是原来的哪个引用类型的地址值。
ref
ref 关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。
例子:
/// <summary>
/// ref测试
/// </summary>
/// <param name="count"></param>
static void RefTest(ref int count)
{
count += ;
Console.WriteLine("In method count: {0}",count);
}
调用结果:
//ref
int count = ;
Console.WriteLine("Before calling method the count is : {0}", count);//输出:After calling method the count is : 10
RefTest(ref count);
Console.WriteLine("After calling method the count is : {0}", count);//输出:After calling method the count is : 20
传递到 ref 参数的参数必须最先初始化。这与 out 不同,out 的参数在传递之前不需要显式初始化。
out
out 关键字会导致参数通过引用来传递。这与 ref 关键字类似,不同之处在于 ref 要求变量必须在传递之前进行初始化。若要使用 out 参数,方法定义和调用方法都必须显式使用 out 关键字。例如:
例子:
/// <summary>
/// out测试
/// </summary>
/// <param name="count"></param>
static void OutTest(out int count)
{
//count += 10;//这样写,编译报错:使用了未赋值的参数"count"
count = ;
Console.WriteLine("In method count: {0}", count);
}
调用:
//out
int count2;
OutTest(out count2);
Console.WriteLine("After calling method the count is : {0}", count2);//输出:After calling method the count is : 10
注意情况:
ref 和 out 关键字在运行时的处理方式不同,但在编译时的处理方式相同。
因此,如果一个方法采用 ref 参数,而另一个方法采用 out 参数,则无法重载这两个方法。
例如,从编译的角度来看,以下代码中的两个方法是完全相同的,因此将不会编译以下代码:
class CS0663_Example
{
public void SampleMethod(out int i) { }
public void SampleMethod(ref int i) { }
}
但是,如果一个方法采用 ref 或 out 参数,而另一个方法不采用这两类参数,则可以进行重载,如下所示
class RefOutOverloadExample
{
public void SampleMethod(int i) { }
public void SampleMethod(out int i) { }
}
当希望方法返回多个值时,声明 out 方法很有用
在函数中,所有out引用的变量都要赋值,ref引用的可以修改,也可以不修改。
2、params --可变参数
params 关键字可以指定在参数数目可变处采用参数的方法参数。
在方法声明中的 params 关键字之后不允许任何其他参数,并且在方法声明中只允许一个 params 关键字。
例子:
/// <summary>
/// 测试Params关键字
/// </summary>
/// <param name="msgList"></param>
static void ParamsTest(params string[] msgList)
{
foreach (string item in msgList)
{
Console.WriteLine(item);
}
}
调用
//测试可变参数
ParamsTest();
ParamsTest("Hello!","GoodBye!");
//输出:
//Hello!
//GoodBye!
ParamsTest("吃了吗?", "吃了!","回见!");
//输出:
//吃了吗?
//吃了!
//回见!
3、可选参数
可以指定过程参数是可选的,并且在调用过程时不必为其提供变量。遵循以下规则:
(1)过程定义中的每个可选参数都必须指定默认值。
(2)可选参数的默认值必须是一个常数表达式。
(3)过程定义中跟在可选参数后的每个参数也都必须是可选的。
例子:
/// <summary>
/// 可选参数
/// </summary>
/// <param name="name"></param>
/// <param name="isMan"></param>
static void OptionalTest(string name, bool isMan = true)
{
if (isMan)
{
Console.WriteLine(name + " is a boy.");
}
else
{
Console.WriteLine(name + " is a girl.");
}
}
调用结果:
//可选参数
OptionalTest("Tom"); //输出: Tom is a boy.
OptionalTest("Lucy",false); //输出:Lucy is a girl
4.命名参数
名称2:参数值2…
命名参数让我们可以在调用方法时指定参数名字来给参数赋值,这种情况下可以忽略参数的顺序。在方法参数很多的情况下很有意义,可以增加代码的可读性。
如下方法声明:
/// <summary>
/// 通常方法
/// </summary>
/// <param name="name">名字</param>
/// <param name="age">年龄</param>
static void Common(string name,int age)
{
Console.WriteLine("The age of " + name + " is " + age + ".");
}
我们可以这样来调用上面声明的方法
//通用方法
Common("Jim", ); //输出:The age of Jim is 20. //命名参数,跟参数顺序无关
Common(name: "Tom", age: ); //输出:The age of Tom is 21.
Common(age: , name: "Tom"); //输出:The age of Tom is 21.
全部测试用例源码:
using System; namespace MethodAnalysis
{
class Program
{
static void Main(string[] args)
{
//通用方法
Common("Jim", ); //输出:The age of Jim is 20. //命名参数,跟参数顺序无关
Common(name: "Tom", age: ); //输出:The age of Tom is 21.
Common(age: , name: "Tom"); //输出:The age of Tom is 21. //ref
int count = ;
Console.WriteLine("Before calling method the count is : {0}", count);//输出:After calling method the count is : 10
RefTest(ref count);
Console.WriteLine("After calling method the count is : {0}", count);//输出:After calling method the count is : 20 //out
int count2;
OutTest(out count2);
Console.WriteLine("After calling method the count is : {0}", count2);//输出:After calling method the count is : 10 //测试可变参数
ParamsTest();
ParamsTest("Hello!","GoodBye!");
//输出:
//Hello!
//GoodBye!
ParamsTest("吃了吗?", "吃了!","回见!");
//输出:
//吃了吗?
//吃了!
//回见! //可选参数
OptionalTest("Tom"); //输出: Tom is a boy.
OptionalTest("Lucy",false); //输出:Lucy is a girl. Console.WriteLine("点击任意键退出");
Console.ReadKey();
} /// <summary>
/// 通常方法
/// </summary>
/// <param name="name">名字</param>
/// <param name="age">年龄</param>
static void Common(string name,int age)
{
Console.WriteLine("The age of " + name + " is " + age + ".");
} /// <summary>
/// ref测试
/// </summary>
/// <param name="count"></param>
static void RefTest(ref int count)
{
count += ;
Console.WriteLine("In method count: {0}",count);
}
/// <summary>
/// 交换字符串
/// 如果不没有使用ref,两个字符串的值是不能互换的
/// </summary>
/// <param name="s1"></param>
/// <param name="s2"></param>
static void SwapStrings(ref string s1, ref string s2)
{
string temp = s1;
s1 = s2;
s2 = temp;
System.Console.WriteLine("Inside the method: {0} {1}", s1, s2);
} /// <summary>
/// out测试
/// </summary>
/// <param name="count"></param>
static void OutTest(out int count)
{
//count += 10;//这样写,编译报错:使用了未赋值的参数"count"
count = ;
Console.WriteLine("In method count: {0}", count);
} /// <summary>
/// 测试Params关键字
/// </summary>
/// <param name="msgList"></param>
static void ParamsTest(params string[] msgList)
{
foreach (string item in msgList)
{
Console.WriteLine(item);
}
} /// <summary>
/// 可选参数
/// </summary>
/// <param name="name"></param>
/// <param name="isMan"></param>
static void OptionalTest(string name, bool isMan = true)
{
if (isMan)
{
Console.WriteLine(name + " is a boy.");
}
else
{
Console.WriteLine(name + " is a girl.");
}
} /// <summary>
/// 可选参数
/// 可选参数,后面只能是可选参数
/// </summary>
/// <param name="name"></param>
/// <param name="isMan"></param>
/// <param name="toys"></param>
static void OptionalTest(string name, bool isMan = true, params string[] toys)
{
if (isMan)
{
Console.WriteLine(name + " is a boy.");
}
else
{
Console.WriteLine(name + " is a girl.");
}
}
}
}
C#方法解析的更多相关文章
- Python的方法解析顺序(MRO)[转]
本文转载自: http://hanjianwei.com/2013/07/25/python-mro/ 对于支持继承的编程语言来说,其方法(属性)可能定义在当前类,也可能来自于基类,所以在方法调用时就 ...
- sqlalchemy mark-deleted 和 python 多继承下的方法解析顺序 MRO
sqlalchemy mark-deleted 和 python 多继承下的方法解析顺序 MRO 今天在弄一个 sqlalchemy 的数据库基类的时候,遇到了跟多继承相关的一个小问题,因此顺便看了一 ...
- iOS 详解NSXMLParser方法解析XML数据方法
前一篇文章已经介绍了如何通过URL从网络上获取xml数据.下面介绍如何将获取到的数据进行解析. 下面先看看xml的数据格式吧! <?xml version="1.0" enc ...
- 四种方法解析JSON数据
(1)使用TouchJSon解析方法:(需导入包:#import "TouchJson/JSON/CJSONDeserializer.h") //使用TouchJson来解析北京的 ...
- Method Resolution Order – Python类的方法解析顺序
在支持多重继承的编程语言中,查找方法具体来自那个类时的基类搜索顺序通常被称为方法解析顺序(Method Resolution Order),简称MRO.(Python中查找其它属性也遵循同一规则.)对 ...
- 【Android 多媒体开发】 MediaPlayer 状态机 接口 方法 解析
作者 : 韩曙亮 转载请著名出处 : http://blog.csdn.net/shulianghan/article/details/38487967 一. MediaPlayer 状态机 介绍 ...
- 2019-2-20C#开发中常用加密解密方法解析
C#开发中常用加密解密方法解析 一.MD5加密算法 我想这是大家都常听过的算法,可能也用的比较多.那么什么是MD5算法呢?MD5全称是 message-digest algorithm 5[|ˈmes ...
- C#中用DateTime的ParseExact方法解析日期时间(excel中使用系统默认的日期格式)
最近做的项目中服务器是英文的系统,系统需要通过excel的单元格导入日期,excel中的日期格式是系统默认的日期格式,如下图所示 以上日期格式,会跟着操作系统设置的日期格式相同例如我的中文系统的日期格 ...
- JSON.parse() 方法解析一个JSON字符串
JSON.parse() 方法解析一个JSON字符串,构造由字符串描述的JavaScript值或对象.可以提供可选的reviver函数以在返回之前对所得到的对象执行变换. 语法EDIT JSON.pa ...
- python 方法解析顺序 mro
一.概要: mor(Method Resolution Order),即方法解析顺序,是python中用于处理二义性问题的算法 二义性: 1.两个基类,A和B都定义了f()方法,c继承A和B那么C调用 ...
随机推荐
- Asp.Net Mvc5 之Controller
经过前面介绍了路由系统之后,我们知道任何一个请求在经过asp.net url路由系统的拦截之后,会生成以controller/action 名称为核心的路由数据.asp.net mvc 根据此解析出目 ...
- 推荐一个国外的vps
也是我遇到过的最廉价的国外的vps,稳定性还不错,用到如今没问题.唯一的缺点就是适合大的企业型的vps卖完了.... ..中文服务,中文界面. 能够用来FQ啊神马的. http://www.hi-vp ...
- 【ALearning】第三章 Android基本常见控件
本章主要介绍主要的寻常较多使用的控件,包含TextView.EditView.ImageView.Button等.本章将介绍相关控件基本属性的使用,为以后章节的进阶学习提供基础.案例中引用的Linea ...
- [node.js]RPC(远程过程调用)的实现原理
刚接触到RPC(远程过程调用),就是可以在本地调用远程机子上的程序的方法,看到一个简单的nodejs实现,用来学习RPC的原理很不错:nodejs light_rpc 使用示例: //服务端 ...
- TOP30专访:捕鱼达人陈昊芝
原文:http://www.csdn.net/article/2012-04-04/313919/1 编者按:3月31日,第四届CocoaChina游戏开发者大会暨Cocos2D-X技术研讨会在北京举 ...
- C++第四章循环
学习时候的点: 1.用户来控制是否继续进行的模板: char goonLoop=’y’; while(goonLoop==’y’){ //logic cout<<”输入y 来继续当前逻辑, ...
- tomcat安装与配置文件
一 安装tomcat 1.系统必须已安装配置JDK 安装说明参考地址:http://www.cnblogs.com/Yuanbangchen/p/5945491.html 2.将apache-to ...
- Linux上安装Squall
Squall是Storm之上的类SQL查询工具,能够将类SQL语句转换成topology,然后提交给Storm运行. 安装Squall前要先安装Java和sbt(simple build tool), ...
- (转)CentOS 6.5下Redis安装详细步骤
Redis简介:Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API.从2010年3月15日起,Redis的开发工作 ...
- aggregation 详解2(metrics aggregations)
概述 权值聚合类型从需要聚合的文档中取一个值(value)来计算文档的相应权值(比如该值在这些文档中的max.sum等). 用于计算的值(value)可以是文档的字段(field),也可以是脚本(sc ...