
正文
<NET CLR via c# 第4版>笔记 第9章 参数
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
9.1 可选参数和命名参数
class Program
{
private static int s_n = 0;
private static void M(int x = 9, string s = "A", DateTime dt = default(DateTime), Guid guid = new Guid())
{
Console.WriteLine("x={0},s={1},dt={2},guid={3}", x, s, dt, guid);
}
public static void Main()
{
//1.等同于M(9,"A",default(DateTime),new Guid());
M();
//2.等同于M(8,"X",default(DateTime),new Guid());
M(8, "X");
//3.等同于M(5,"A",DateTime.Now,Guid.NewGuid());
M(5, guid: Guid.NewGuid(), dt: DateTime.Now);
//4.等同于M(0,"1",default(DateTime),new Guid());
M(s_n++, s_n++.ToString());
//5.等同于以下两行代码:
//string t1="2";int t2=3;
//M(t2,t1,default(DateTime),new Guid());
M(s: (s_n++).ToString(), x: s_n++);
}
}
9.1.1 规则和原则
-
可为方法、构造器方法和有参属性(C#索引器)的参数指定默认值。还可为属于委托定义一部分的参数指定默认值。
-
有默认值的参数必须放在没有默认值的所有参数之后。但有一个例外:“参数数组”这种参数必须放在所有参数(包括有默认值的这些)之后,而且数组本身不能有一个默认值。
-
默认值必须是编译时能确定的常量值(包括基元类型、枚举类型,以及能设为null的任何引用类型)。值类型的参数可将默认值设为值类型的实例,并让它的所有字段都包含零值。可用 default 或 new 关键字来表达这个意思,两种语法生成的IL代码完全一致。
-
不要重命名参数变量,否则任何调用者以传参数名的方式传递实参,它们的代码也必须修改。
-
如果方法从模块外部调用,更改参数的默认值具有潜在的危险性 。call site(发出调用的地方)在它的调用中嵌入默认值。如果以后更改了参数的默认值,但没有重新编译包含call site的代码,它在调用你的方法时就会传递旧的默认值。 可考虑将默认值 0/null 作为哨兵值使用 ,从而指出默认行为。例子:
//不要这样做:
private static string MakePath(string filename = "Untitled")
{
return string.Format(@"c\{0}.txt", filename);
}
//而要这样做:
private static string MakePath(string filename = null)
{
return string.Format(@"C:\{0}.txt", filename ?? "Untitled");
}
- 如果参数用 ref 或 out 关键字进行了标识,就不能设置默认值。
使用可选或命名参数调用方法时,还要注意以下附加的规则和原则:
-
实参可按任意顺序传递, 但命名实参只能出现在实参列表的尾部 。
-
可按名称将实参传给没有默认值的参数,但所有必须的实参都必须传递(无论按位置还是按名称)。
-
C#不允许省略逗号之间的实参,比如
M(1,,DateTime.Now)。对于有默认值的参数,如果想省略它们的实参,以传参数名的方式传递实参即可。 -
如果参数要求 ref/out ,为了以传参数名的方式传递实参,请使用下面这样的语法:
//方法声明:
private static void M(ref int x) { ...}
//方法调用:
int a = 5;
M(x: ref a);
- C#调用COM组件时,如果是以传引用的方式传递实参,C#还允许省略 ref/out ,进一步简化编码。但如果调用的不是COM组件,C#就要求必须向实参应用 ref/out 关键字 。
9.1.2 DefaultParameterValueAttribute 和 OptionalAttribute
9.2 隐式类型的局部变量
-
不能用 var 声明方法的参数类型。
-
不能用 var 声明类型中的字段。
-
不要混淆 dynamic 和 var 。用 var 声明局部变量只是一种简化语法,它要求编译器根据表达式推断具体数据类型。 var 关键字只能声明方法内部的局部变量,而 dynamic 关键字适用于局部变量、字段和参数。表达式不能转型为 var ,但能转型为 dynamic 。必须显式初始化用 var 声明的变量,但无需初始化用 dynamic 声明的变量。
private static void ImplicitlyTypedLocalVariables()
{
var name = "Jeff";
ShowVariableType(name); //显示:System.String
//var n=null; //错误,不能将null赋给隐式类型的局部变量
var x = (String)null; //可以这样写,但意义不大
ShowVariableType(x); //显示:System.String
var numbers = new int[] { 1, 2, 3, 4 };
ShowVariableType(numbers); //显示:System.Int32[]
//复杂类型能少打一些字
var collection = new Dictionary<String, Single>() { { "Grant", 4.0f } };
//显示:System.Collections.Generic.Dictionary`2[System.String,System.Single]
ShowVariableType(collection);
foreach (var item in collection)
{
//显示:System.Collections.Generic.KeyValuePair`2[System.String,System.Single]
ShowVariableType(item);
}
}
private static void ShowVariableType<T>(T t)
{
Console.WriteLine(typeof(T));
}
9.3 以传引用的方式向方法传递参数
-
CLR 默认所有方法参数都传值。
-
CLR 允许以传引用而非传值的方式传递参数。C# 用关键字 out 或 ref 支持这个功能。
-
CLR 不区分 out 和 ref ,无论用哪个关键字,都会生成相同的 IL 代码。另外,元数据也几乎完全一致,只有一个bit除外,它用于记录声明方法时指定的是 out 还是 ref 。
-
C#编译器是将这两个关键字区别对待的,而且这个区别决定了由哪个方法负责初始化所引用的对象。
-
使用 out 标记参数的方法,不能读取该参数的值,而且在返回前必须向这个值写入。相反,如果用 ref 标记方法,必须在调用方法前初始化参数的值,被调用的方法可以读取值以及、或者向值写入 ;
-
使用 out
public static void Main()
{
int x; //x没有初始化
GetVal(out x); //x不必初始化
Console.WriteLine(x); //显示“10”
}
private static void GetVal(out int v)
{
v = 10; //该方法必须初始化v
}
- 使用 ref
public static void Main()
{
int x = 5; //x已经初始化
GetVal(ref x); //x必须初始化
Console.WriteLine(x); //显示“15”
}
private static void GetVal(ref int v)
{
v += 10; //该方法可使用v的已初始化的值
}
-
不能定义仅在 ref 和 out 上有差别的重载方法。
-
以传引用的方式传给方法的变量,它的类型必须与方法签名中声明的类型相同。
public static void Main()
{
string s1 = "Jeffrey";
string s2 = "Richter";
//错误!错误!错误!
//Swap(ref s1, ref s2);
//以传引用的方式传递的变量,
//必须和方法预期的匹配
object o1 = s1, o2 = s2;
Swap(ref o1,ref o2);
//完事后再将object转型为string
s1 = (string)o1;
s2 = (string)o2;
Console.WriteLine(s1); //显示“Richter”
Console.WriteLine(s2); //显示“Jeffrey”
}
private static void Swap(ref object a, ref object b)
{
object t = b;
b = a;
a = t;
}
- 可用泛型来修正上面方法
public static void Main()
{
string s1 = "Jeffrey";
string s2 = "Richter";
Swap(ref s1, ref s2);
Console.WriteLine(s1); //显示“Richter”
Console.WriteLine(s2); //显示“Jeffrey”
}
private static void Swap<T>(ref T a, ref T b)
{
T t = b;
b = a;
a = t;
}
9.4 向方法传递可变数量的参数
-
params 只能应用于方法签名中的最后一个参数。
-
这个参数只能标识一维数组(任意类型)。
-
可为这个参数传递 null 值,或传递对包含零个元素的一个数组的引用。
-
调用参数数量可变的方法对性能有所影响(除非显式传递null) 。要减少对性能的影响,可考虑定义几个没有使用 params 关键字的重载版本,如
System.String类的 Concat 方法。
public static void Main()
{
Console.WriteLine(Add(new int[] { 1, 2, 3, 4, 5 }));//显示“15”
//或
Console.WriteLine(Add(1, 2, 3, 4, 5)); //显示“15”
//以下两行都显示“0”
Console.WriteLine(Add()); //向Add传递 new int[0]
Console.WriteLine(Add(null)); //向Add传递 null :更高效(因为不会分配数组)
}
private static int Add(params int[] values)
{
// 注意:如果愿意,可将values数组传给其他方法
int sum = 0;
if (values != null)
{
for (int x = 0; x < values.Length; x++)
sum += values[x];
}
return sum;
}
9.5 参数和返回类型的设计规范
-
声明方法的参数类型时,应尽量指定最弱的类型,宁愿要接口也不要基类
。例如,如果要写方法来处理一组数据项,最好是用接口(比如
IEnumerable<T>)声明参数,而不要用强数据类型(比如List<T>)或者更强的接口类型(比如ICollection<T>或IList<T>):
//好:方法使用弱参数类型
public void ManipulateItems<T>(IEnumerable<T> collection){}
//不好:方法使用强参数类型
public void ManipulateItems<T>(List<T> collection) { }
- 相反,一般最好是将方法的返回类型声明为最强的类型(防止受限于特定类型)。例如,方法最好返回 FileStream 而不是 Stream 对象:
//好:方法使用强返回类
public FileStream OpenFile() { }
//不好:方法使用弱返回类
public Stream OpenFile() { }
- 如果想保持一定的灵活性,在将来更改方法返回的东西,请选择一个较弱的返回类型。
//灵活:方法使用较弱的返回类型
public IList<string> GetStringCollection() { }
//不灵活:方法使用较强的返回类型
public List<string> GetStringCollection() { }
9.6 常量性
返回目录
<NET CLR via c# 第4版>笔记 第9章 参数的更多相关文章
-
<NET CLR via c# 第4版>笔记 第19章 可空值类型
System.Nullable<T> 是结构. 19.1 C# 对可空值类型的支持 C# 允许用问号表示法来声明可空值类型,如: Int32? x = 5; Int32? y = null ...
-
<NET CLR via c# 第4版>笔记 第18章 定制特性
18.1 使用定制特性 FCL 中的几个常用定制特性. DllImport 特性应用于方法,告诉 CLR 该方法的实现位于指定 DLL 的非托管代码中. Serializable 特性应用于类型,告诉 ...
-
<NET CLR via c# 第4版>笔记 第17章 委托
17.1 初识委托 .net 通过委托来提供回调函数机制. 委托确保回调方法是类型安全的. 委托允许顺序调用多个方法. 17.2 用委托回调静态方法 将方法绑定到委托时,C# 和 CLR 都允许引用类 ...
-
<NET CLR via c# 第4版>笔记 第16章 数组
//创建一个一维数组 int[] myIntegers; //声明一个数组引用 myIntegers = new int[100]; //创建含有100个int的数组 //创建一个二维数组 doubl ...
-
<NET CLR via c# 第4版>笔记 第13章 接口
13.1 类和接口继承 13.2 定义接口 C#用 interface 关键字定义接口.接口中可定义方法,事件,无参属性和有参属性(C#的索引器),但不能定义任何构造器方法,也不能定义任何实例字段. ...
-
<NET CLR via c# 第4版>笔记 第12章 泛型
泛型优势: 源代码保护 使用泛型算法的开发人员不需要访问算法的源代码.(使用c++模板的泛型技术,算法的源代码必须提供给使用算法的用户) 类型安全 向List<DateTime>实例添加一 ...
-
<NET CLR via c# 第4版>笔记 第5章 基元类型、引用类型和值类型
5.1 编程语言的基元类型 c#不管在什么操作系统上运行,int始终映射到System.Int32; long始终映射到System.Int64 可以通过checked/unchecked操作符/语句 ...
-
<NET CLR via c# 第4版>笔记 第6章 类型和成员基础
6.1 类型的各种成员 6.2 类型的可见性 public 全部可见 internal 程序集内可见(如忽略,默认为internal) 可通过设定友元程序集,允许其它程序集访问该程序集中的所有inte ...
-
<NET CLR via c# 第4版>笔记 第7章 常量和字段
7.1 常量 常量 是值从不变化的符号.定义常量符号时,它的值必须能够在编译时确定. 只能定义编译器识别的基元类型的常量,如果是非基元类型,需把值设为null. 常量的值直接嵌入代码,所以不能获取常量 ...
随机推荐
-
python之动态参数 *args,**kwargs(聚合,打散--转载
转自https://www.cnblogs.com/ellisonzhang/p/10243122.html 一.函数的动态参数 *args,**kwargs, 形参的顺序 1.你的函数,为了拓展,对 ...
-
H5保养
合成油上面写着A3B4级,可以用的.绿静发动机说明书上写着呢CI-4级或A3B4级都可以用. 你的车换机油要加多少升? 5.6标准数,先加5L后看机油尺,在中间就行, 多点少点只要不过上线就无所谓. ...
-
mysql 数据操作 单表查询 having 过滤 练习
1. 查询各岗位内包含的员工个数小于2的岗位名.岗位内包含员工名字.个数 mysql> select post,group_concat(name),count(id) from employe ...
-
js-jquery-从SweetAlert到SweetAlert2
原文地址:https://github.com/limonte/sweetalert2/wiki/Migration-from-SweetAlert-to-SweetAlert2 1. IE supp ...
-
EasyUI Pagination 分页
通过 $.fn.pagination.defaults 重写默认的 defaults. 分页(pagination)允许用户通过翻页导航数据.它支持页面导航和页面长度选择的可配置选项.用户可以在分页的 ...
-
C语言——stdio.h
int fgetc(FILE * stream); get character from stream 返回流中的一个字符,并以int的类型返回,如果碰到文件的结尾,或者一个错误发生,函数返回 ...
-
问题:ORA-28000: the account is locked 用户锁住了。
打开cmd: 执行 sqlplus /nolog 执行conn / as sysdba 执行 ALTER USER username ACCOUNT UNLOCK;
-
FTP服务器配置实践
1.为linux系统分配IP地址:192.168.X.1/24,并重启网络服务,客户端XP系统IP地址为:192.168.X.2/24, 2.查询本机是否安装了vsftpd服务,结果显示未安装,挂载光 ...
-
facebook graph api 报错SSLError(1, u'[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:661)')
使用facebook graph api,报错如下 一开始以为是https证书验证失败,查了一下午源码,没有看到问题,于是把Python27\lib\site-packages\requests\ad ...
-
Flex与SSH集成
Flex与SSH集成 -- ::| 分类: flex |举报|字号 订阅 Flex与SSH集成 ,下载blazeds_bin_3---.zip 包,将其解压 取下blazeds.war包 更改为bla ...
System.Nullable<T> 是结构. 19.1 C# 对可空值类型的支持 C# 允许用问号表示法来声明可空值类型,如: Int32? x = 5; Int32? y = null ...
18.1 使用定制特性 FCL 中的几个常用定制特性. DllImport 特性应用于方法,告诉 CLR 该方法的实现位于指定 DLL 的非托管代码中. Serializable 特性应用于类型,告诉 ...
17.1 初识委托 .net 通过委托来提供回调函数机制. 委托确保回调方法是类型安全的. 委托允许顺序调用多个方法. 17.2 用委托回调静态方法 将方法绑定到委托时,C# 和 CLR 都允许引用类 ...
//创建一个一维数组 int[] myIntegers; //声明一个数组引用 myIntegers = new int[100]; //创建含有100个int的数组 //创建一个二维数组 doubl ...
13.1 类和接口继承 13.2 定义接口 C#用 interface 关键字定义接口.接口中可定义方法,事件,无参属性和有参属性(C#的索引器),但不能定义任何构造器方法,也不能定义任何实例字段. ...
泛型优势: 源代码保护 使用泛型算法的开发人员不需要访问算法的源代码.(使用c++模板的泛型技术,算法的源代码必须提供给使用算法的用户) 类型安全 向List<DateTime>实例添加一 ...
5.1 编程语言的基元类型 c#不管在什么操作系统上运行,int始终映射到System.Int32; long始终映射到System.Int64 可以通过checked/unchecked操作符/语句 ...
6.1 类型的各种成员 6.2 类型的可见性 public 全部可见 internal 程序集内可见(如忽略,默认为internal) 可通过设定友元程序集,允许其它程序集访问该程序集中的所有inte ...
7.1 常量 常量 是值从不变化的符号.定义常量符号时,它的值必须能够在编译时确定. 只能定义编译器识别的基元类型的常量,如果是非基元类型,需把值设为null. 常量的值直接嵌入代码,所以不能获取常量 ...
-
python之动态参数 *args,**kwargs(聚合,打散--转载
转自https://www.cnblogs.com/ellisonzhang/p/10243122.html 一.函数的动态参数 *args,**kwargs, 形参的顺序 1.你的函数,为了拓展,对 ...
-
H5保养
合成油上面写着A3B4级,可以用的.绿静发动机说明书上写着呢CI-4级或A3B4级都可以用. 你的车换机油要加多少升? 5.6标准数,先加5L后看机油尺,在中间就行, 多点少点只要不过上线就无所谓. ...
-
mysql 数据操作 单表查询 having 过滤 练习
1. 查询各岗位内包含的员工个数小于2的岗位名.岗位内包含员工名字.个数 mysql> select post,group_concat(name),count(id) from employe ...
-
js-jquery-从SweetAlert到SweetAlert2
原文地址:https://github.com/limonte/sweetalert2/wiki/Migration-from-SweetAlert-to-SweetAlert2 1. IE supp ...
-
EasyUI Pagination 分页
通过 $.fn.pagination.defaults 重写默认的 defaults. 分页(pagination)允许用户通过翻页导航数据.它支持页面导航和页面长度选择的可配置选项.用户可以在分页的 ...
-
C语言——stdio.h
int fgetc(FILE * stream); get character from stream 返回流中的一个字符,并以int的类型返回,如果碰到文件的结尾,或者一个错误发生,函数返回 ...
-
问题:ORA-28000: the account is locked 用户锁住了。
打开cmd: 执行 sqlplus /nolog 执行conn / as sysdba 执行 ALTER USER username ACCOUNT UNLOCK;
-
FTP服务器配置实践
1.为linux系统分配IP地址:192.168.X.1/24,并重启网络服务,客户端XP系统IP地址为:192.168.X.2/24, 2.查询本机是否安装了vsftpd服务,结果显示未安装,挂载光 ...
-
facebook graph api 报错SSLError(1, u'[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:661)')
使用facebook graph api,报错如下 一开始以为是https证书验证失败,查了一下午源码,没有看到问题,于是把Python27\lib\site-packages\requests\ad ...
-
Flex与SSH集成
Flex与SSH集成 -- ::| 分类: flex |举报|字号 订阅 Flex与SSH集成 ,下载blazeds_bin_3---.zip 包,将其解压 取下blazeds.war包 更改为bla ...






