一起谈.NET技术,谈谈C# 4.0新特性“缺省参数”的实现

  C#4.0关于缺省参数的新特性,相信大家都不会陌生。所谓缺省参数,顾名思义,就是在声明方法的某个参数的时候为之指定一个默认值,在调用该方法的时候如果采用该默认值,你就无须指定该参数。和很多语言层面特性(语法糖)的实现一样,缺省参数也是编译器为我们玩的一个小花招。缺省参数最终体现为两个特殊的自定义特性OptionalAttribute和DefaultParameterValueAttribute 。

目录
一、缺省参数的用法
二、实现缺省参数的两个特性:OptionalAttribute和DefaultParameterValueAttribute
三、直接通过OptionalAttribute和DefaultParameterValueAttribute 定义缺省参数

  一、缺省参数的用法

  比如下面一个TestMethod方法,后面两个参数bar和baz就是缺省参数,默认值分别为“Bar”和“Baz”。


static void TestMethod(string foo, string bar = "Bar", string baz = "Baz")
{
Console.WriteLine("{0, -5} - {1, -5} - {2, -5}", foo, bar, baz);
}

  在调用TestMethod的时候,我们自由地选择采用缺省的参数值,或者覆盖该缺省值。


static void Main(string[] args)
{
TestMethod("Foo");
TestMethod("Foo", "Bar1");
TestMethod("Foo", "Bar1", "Baz1");
}

  下面是输出结果:


Foo - Bar - Baz
Foo - Bar1 - Baz
Foo - Bar1 - Baz1

  缺省参数的使用有两个简单的限制,其一是:缺省参数的声明只能放在普通参数之后。如下代码中定义的TestMethod方法中,缺省参数bar后面跟一个非缺省参数baz,这样的代码是不能通过编译的(编译错误信息为:Optional parameters must appear after all required parameters)。


static void TestMethod(string foo, string bar = "Bar", string baz)
{
Console.WriteLine("{0, -5} - {1, -5} - {2, -5}", foo, bar, baz);
}

  但是,缺省参数后面可以跟数组参数(params参数),实际上无论在什么情况下,params参数都只能是最后一个声明的参数。关于缺省参数的声明的位置限制,主要重载方法的识别机制决定的,这一点大家都很容易理解。

  缺省参数的另一个限制是:指定的缺省值必须是一个常量,这就实际上为作为缺省参数的数据类型作了限制——只能是系统定义的基元类型。下面定义的TestMethod方法中,我们定义了一个DateTime类型的缺省参数,并将参数缺省值作为DateTime.Now。由于DateTime.Now不是常量,所以这样的代码也不能通过编译(编译错误消息:Default parameter value for 'date' must be a compile-time constant)。


static void TestMethod(DateTime date = DateTime.Now)
{
//Others...
}

  二、实现缺省参数的两个特性:OptionalAttribute和DefaultParameterValueAttribute

  为什么缺省参数的默认值只能接受常量呢?如果你了解了缺省参数的本质,这就不是一个问题。那么缺省参数究竟是如何实现的呢?

  和很多语言层面特性(语法糖)的实现一样,缺省参数也是编译器为我们玩的一个小花招,而真正编译后的东西都是我们再熟悉不过的玩意儿。当包含缺省参数的C#代码经过编译后,缺省参数体现在两个特殊的自定义特性OptionalAttribute和DefaultParameterValueAttribute 。前者将参数标识为缺省参数,后者指定其缺省值。


[ComVisible(true), AttributeUsage(AttributeTargets.Parameter, Inherited=false)]
public sealed class OptionalAttribute : Attribute
{
}

[AttributeUsage(AttributeTargets.Parameter)]
public sealed class DefaultParameterValueAttribute : Attribute
{
public DefaultParameterValueAttribute(object value);
public object Value {get; }
}

  对于最开始我们定义的TestMethod方法,编译后的形式如下所示。


private static void TestMethod(string foo,
[Optional, DefaultParameterValue("Bar")] string bar,
[Optional, DefaultParameterValue("Baz")] string baz)
{
//Others..
}

  正是因为缺省参数的默认值最终是作为DefaultParameterValueAttribute的参数存在的,所以它必须是常量。

  三、直接通过OptionalAttribute和DefaultParameterValueAttribute 定义缺省参数

  既然缺省参数最终体现为OptionalAttribute和DefaultParameterValueAttribute 这两个特性,我们是否可以直接通过它们来定义缺省参数呢?答案是:当然可以,下面的代码一样可以正常执行。


static void Main(string[] args)
{
TestMethod("Foo");
TestMethod("Foo","Bar1");
TestMethod("Foo","Bar1","Baz1");
}

private static void TestMethod(string foo,
[Optional, DefaultParameterValue("Bar")] string bar,
[Optional, DefaultParameterValue("Baz")] string baz)
{
//Others..
}

  如果调用含有缺省参数的方法,并且没有显示指定该参数,编译器在编译的时候会自动将默认值附加上去。对于上面的Main方法,下面是与之等效的编译后代码。


private static void Main(string[] args)
{
TestMethod("Foo", "Bar", "Baz");
TestMethod("Foo", "Bar1", "Baz");
TestMethod("Foo", "Bar1", "Baz1");
}

  虽然说我们通过OptionalAttribute和DefaultParameterValueAttribute 这两个特性也可以定义缺省参数,但是当我们将缺省参数定义在普通参数之前是,编译器不会报错。倒是方法中缺省参数实际上就相当于普通参数了。


static void Main(string[] args)
{
//TestMethod("Foo","Baz");
//上面的方法调用无效
TestMethod("Foo","Bar1","Baz1");
}
private static void TestMethod(string foo,
[Optional, DefaultParameterValue("Bar")] string bar,
string baz)
{
//Others..
}

时间: 2024-08-31 03:23:26

一起谈.NET技术,谈谈C# 4.0新特性“缺省参数”的实现的相关文章

谈谈C# 4.0新特性“缺省参数”的实现

转自 http://www.cnblogs.com/artech/archive/2011/01/12/optionalparameter.html   C#4.0关于缺省参数的新特性,相信大家都不会陌生.所谓缺省参数,顾名思义,就是在声明方法的某个参数的时候为之指定一个默认值,在调用该方法 的时候如果采用该默认值,你就无须指定该参数.和很多语言层面特性(语法糖)的实现一样,缺省参数也是编译器为我们玩的一个小花招.缺省参数最终体现为两 个特殊的自定义特性OptionalAttribute和Def

“.NET研究”谈谈C# 4.0新特性“缺省参数”的实现

C#4.0关于缺省参数的新特性,相信大家都不会陌生.所谓缺省参数,顾名思义,就是在声明方法的某个参数的时候为之指定一个默认值,在调用该方法的时候如果采用该默认值,你就无须指定该参数.和很多语言层面特性(语法糖)的实现一样,缺省参数也是编译器为我们玩的一个小花招.缺省参数最终体现为两个特殊的自定义特性OptionalAttribute和DefaultParameterValueAttribute . 目录 一.缺省参数的用法 二.实现缺省参数的两个特性:OptionalAttribute和Defa

一起谈.NET技术,.NET 4的新特性:图表、SEO及可扩展的输出缓存

即将发布的.NET Framework 4.0拥有众多的新改进,此前InfoQ已经对其进行了详尽的报道.本文将再来揭示.NET 4.0中的3个新特性:图表控件.SEO支持以及ASP.NET 4可扩展的输出缓存. 图表控件 微软向开发者提供了大量可免费下载的图表控件,可以在.NET 3.5 ASP.NET或WinForms项目中使用这些控件.要想在Visual Studio 2008中使用这些控件则需要安装一个插件,该插件提供了VS工具箱及智能集成功能.现在这些控件已经集成到了.NET 4.0中,

一起谈.NET技术,.NET 3.x新特性之自动属性及集合初始化

今天公司弄了个VS2008 beta 2中文版,虽然很大一部分是为了JS的智能提示外,也应该好好的温习一下.NET的一些新特性,由于以前写过一些文章,但是都没有系统的学过,都只是尝一下新鲜感.不知道从那开始,所以今天就来看看自动话属性,以及对象初始化和集合初始化的一些新特性. 1.自动属性 在做一个程序是我们离不开属性,特别是实体类.我们用指头一个一个的敲着get和set及局部的变量(Fields),现在可好不用在重复敲那些东东了我们只要用到get和set,就和我们的接口声明差不多了,是不是很h

MySQL · 8.0.0新特性 · 持久化全局参数修改

PS: 本文内容基于MySQL8.0.0版本,由于目前才Release了第一个开发版本,不排除后续行为会发生变化 相信很多朋友都有这样的体验,在实例启动的时候动态修改了某些配置,但是忘了修改配置文件,结果实例一重启修改就丢失了.或者对于诸如部署在云上的业务(例如RDS),通常用户是没有修改配置文件的权限的,这导致配置的设定不够灵活.从MySQL8.0开始,大家不用担心这个问题了,用户可以选择性的将配置进行持久化. 对应的Worklog: WL#8688 启用这个功能,使用特定的语法SET PER

C#4.0新特性 可选命名参数

Code    class Program    {        static void PrintStudents(int id = -1, string name = "*", int age = -1)        {            Console.WriteLine("the student is id:{0} name:{1} age:{2}", id, name, age);        }        static void Main(

[C#]6.0新特性浅谈

原文:[C#]6.0新特性浅谈 C#6.0出来也有很长一段时间了,虽然新的特性和语法趋于稳定,但是对于大多数程序猿来说,想在工作中用上C#6.0估计还得等上不短的一段时间.所以现在再来聊一聊新版本带来的新特性可能也还不算晚吧? 一.nameof关键字 这绝对是整个新版本最让我期待的内容,它给代码重构带来了巨大的便利.先来看一下它是怎么使用的吧: string s; Console.WriteLine(nameof(s)); s = nameof(s.Length); Console.WriteL

MySQL 5.0新特性教程 存储过程:第一讲

mysql|存储过程|教程 作者:mysql AB;翻译:陈朋奕 Introduction 简介 MySQL 5.0 新特性教程是为需要了解5.0版本新特性的MySQL老用户而写的.简单的来说是介绍了"存储过程.触发器.视图.信息架构视图",在此感谢译者陈朋奕的努力. 希望这本书能像内行专家那样与您进行对话,用简单的问题.例子让你学到需要的知识.为了达到这样的目的,我会从每一个细节开始慢慢的为大家建立概念,最后会给大家展示较大的实用例,在学习之前也许大家会认为这个用例很难,但是只要跟着

ASP 3.0新特性概要

 ASP 3.0新特性概要 在ASP3.0中,有一些新的特性或经历较大的变化或改进的特性.1. 无脚本的ASPASP处理不包括任何脚本的.asp页的速度是很快的,假如你正在创建的站点或Web应用程序文件最终可能使用ASP,最好让这些文件使用.asp文件扩展名,而不用考虑它们是包含服务器端脚本还是仅仅包含静态(HTML和文本)内容. 2. 新的流向控制能力到目前为止,假如想把执行转向另外的一个ASP页,不得不使用Response.Redirect语句,这个工作通过向客户端发送一个响应来指示其载入新