1、可选参数和命名实参

可选参数和命名实参就如同一对好基友,因为它们经常一起使用。

1.1 可选参数

可选参数重在“可选”,即在调用方法时,该参数可以明确指定实参,也可以不指定。如下代码所示,下面代码就包含3个参数,一个必备参数和两个可选参数。

 static void TestMethod(int x,int y=,string name="LearningHard")
{
Console.WriteLine($"x={x} y={y} name={name}");
}

在以上代码中,参数x是必选参数,即调用方法必须指定实参,而其他剩余的两个参数可以不用指定实参,当然,显式的指定也是可以的,如果进行显式地指定了实参,则它们的值就被初始化为实参的值。下面几句代码皆是调用上面方法。

 static void Main(string[] args)
{
TestMethod(,,"Hello");
TestMethod(,);
TestMethod();
Console.ReadKey();
}

在使用可选参数时,需要注意一下几个约束条件:

(1)所有可选参数必须位于必选参数之后。

(2)可选参数的默认值必须为常量,如数字、常量字符串、null、const成员和枚举成员等。

(3)参数数组(由params 修饰声明)不能为可选参数。

(4)用ref或out关键字标识的参数不能被设置为可选参数。

1.2、命名实参

当调用带有可选参数的方法时,如果我们省略了一个参数,编译器默认我们省略的是最后一个参数。但是如果我们只想省略第二个参数该怎么办呢?命名实参可以解决这个问题。

TestMethod(,name:"Hello");
TestMethod(x:,y:,name:"Hello");

以上代码就使用了命名实参的方法调用。从代码可以看出,命名实参就是在为实参指定具体的名称,这样编译器将判断参数的名称是否正确,然后将指定的值赋给对应的参数,从而达到只省略第二个参数的目的。

1.3 COM互操作的福音

可选参数和命名实参是C#4.0中最简单的两个特性,它们最大的好处是简化了C#与COM组件的互操作。COM(Component Object Model,即组件对象模型)。

2、泛型的可变性

在C#2.0中,泛型并不具备可变性,这种可变性是指协变性和逆变性。在面向对象中,继承就蕴含可变性,当方法声明返回的类型为Stream时,可以在实现中返回一个FileStream类型,这里就存在一个隐式的转化:从FileStream类型(子类引用)转换为Stream(父类引用)。引用类型的数组也存在这种从子类引用到父类引用的转化,例如string[]可以转化为object[]。

2.1 协变性

协变性指的是泛型类型参数可以从一个派生类隐式地转化为基类。C#4.0引入out关键字来标记泛型参数,以示支持协变性。

  List<object> listObject=new List<object>();
List<string> listStrs=new List<string>();
listObject.AddRange(listStrs);
//listStrs.AddRange(listObject);这是错误的

在以上的代码中,AddRange方法接收的参数类型为IEnumerable<T>,该接口的定义为IEnumerable<out T>,因为其泛型参数有out关键字标识,所以用这个类型的参数T支持协变性,则可以将List<String>转化为IEnumerable<string>(这是被继承的协变性支持的,因为List<T>实现了IEnumerable<T>接口)。又因为类型参数支持协变性,所以可以进一步把IEnumerable<string>转化为IEnumerable<object>类型。这样,代码listobject.AddRange(liststrs)就是正确的,不会出现编译错误。

2.2 逆变性

逆变性指的是泛型类型参数可以从一个基类隐式地转化为派生类,C# 4.0引入in关键字来标记泛型参数,以示支持逆变性。下面以.NET类库中的接口public interface IComparer<in T>为例进行演示。

   List<object> listObject=new List<object>();
List<string> listStrs=new List<string>(); IComparer<object> objComparer = new TestComparer();
IComparer<string> stringComparer=new TestComparer(); listStrs.Sort(objComparer);
//listObject.Sort(stringComparer);这是错误的 internal class TestComparer : IComparer<object>
{
public int Compare(object x, object y)
{
throw new NotImplementedException();
}
}

在以上代码中,listStrs变量的Sort方法应接收IComparer<string>类型的参数,虽然传入的实参为IComparer<object>类型,但因为IComparer< in T>泛型接口支持逆变,所以可将object转化为string类型,于是代码listStrs.Sort(objComparer)也就可以通过编译了。

2.3 协变和逆变的注意事项

并不是所有类型都支持泛型类型参数的协变和逆变性,下面总结使用这两个特性时需要注意的地方。

(1)只有接口和委托才支持协变和逆变(如Func<out TResult>、Action<in T>),类或泛型方法的类型参数都不支持协变和逆变。

(2)协变和逆变只适用于引用类型,值类型不支持协变和逆变,所以List<int>无法转化为IEnumerable<object>。

(3)必须显式地用in或out来标记类型参数。

(4)委托的可变性不要在多播委托中使用。

很多人可能会问关于第4点的问题,下面用代码演示一下:

             Func<string> stringFunc = () => "";
Func<Object> objectFunc=()=>new object();
Func<object> combined = stringFunc + objectFunc;

这段代码在运行的时候会出现问题的,异常信息为:委托必须具有相同的类型。

因为Delegate.Combine方法要求参数必须为相同类型。所以上面的代码如果要正确运行,需要进行一下修改:

             Func<string> stringFunc = () => "";
Func<Object> objectFunc=()=>new object(); Func<object> objectFunc2=new Func<object>(stringFunc);
Func<object> combined = objectFunc2 + objectFunc;

强制转换之后,就可以调用Delegate.Combine方法时确定要创建的委托类型了,从而解决了运行时抛出异常的问题。

小改动,大作为——C# 4.0中的微小改动的更多相关文章

  1. 手摸手教你如何在 Python 编码中做到小细节大优化

    手摸手教你如何在 Python 编码中做到小细节大优化 在列表里计数 """ 在列表里计数,使用 Python 原生函数计数要快很多,所以尽量使用原生函数来计算. &qu ...

  2. EF Core 1.0中使用Include的小技巧

    (此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:由于EF Core暂时不支持Lazy Loading,所以利用Include来加载额外 ...

  3. [读书笔记]C#学习笔记七: C#4.0中微小改动-可选参数,泛型的可变性

    前言 下面就开始总结C#4.0的一些变化了, 也是这本书中最后的一点内容了, 这一部分终于要更新完了. 同时感觉再来读第二遍也有不一样的收获. 今天很嗨的是武汉下雪了,明天周六,一切都是这么美好.哈哈 ...

  4. Web Api 2.0中使用Swagger生成Api文档的2个小Tips

    当Web Api 2.0使用OAuth2授权时,如何在Swagger中添加Authorization请求头? Swagger说明文档支持手动调用Api, 但是当Api使用OAuth2授权时,由于没有地 ...

  5. 【OpenCV】opencv3.0中的SVM训练 mnist 手写字体识别

    前言: SVM(支持向量机)一种训练分类器的学习方法 mnist 是一个手写字体图像数据库,训练样本有60000个,测试样本有10000个 LibSVM 一个常用的SVM框架 OpenCV3.0 中的 ...

  6. Core 1.0中的管道-中间件模式

    ASP.NET Core 1.0中的管道-中间件模式 SP.NET Core 1.0借鉴了Katana项目的管道设计(Pipeline).日志记录.用户认证.MVC等模块都以中间件(Middlewar ...

  7. Apache Spark 2.2.0 中文文档

    Apache Spark 2.2.0 中文文档 - 快速入门 | ApacheCN Geekhoo 关注 2017.09.20 13:55* 字数 2062 阅读 13评论 0喜欢 1 快速入门 使用 ...

  8. Vue2.0 中,“渐进式框架”和“自底向上增量开发的设计”这两个概念是什么?(转)

    https://www.zhihu.com/question/51907207?rf=55052497 徐飞 在我看来,渐进式代表的含义是:主张最少. 每个框架都不可避免会有自己的一些特点,从而会对使 ...

  9. AppBox v6.0中实现子页面和父页面的复杂交互

    前言 1. AppBox是捐赠开源(获取源代码至少需要捐赠作者 1 元钱),基于的 FineUI(开源版)则是完整开源,网址:http://fineui.codeplex.com/ 2. 你可以通过捐 ...

随机推荐

  1. Java笔记(二十二)……Collection集合

    概述 为什么会出现集合类 面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式 数组和集合类同是容器,有何不同 数组虽然也可以存储 ...

  2. java中字符串切割的方法总结

    StringTokenizer最快 ,基本已经不用了,除非在某些需要效率的场合.Scanner最慢. String和Pattern速度差不多.Pattern稍快些. String和Pattern的sp ...

  3. 用 ggplot2 在同一个图上画多条颜色不同的线

    假如数据格式是这样: day    邓文迪    微博    城管0    0.0    9.262970888519191E-4    0.01    0.0    0.00144775855013 ...

  4. java操作pdf添加页眉条码添加水印图片

    添加条码页眉以及图片水印 1. 引入jar包     1. itext-4.2.1.jar     2. itext-asian-5.2.0.jar     3. jbarcode-0.2.8.jar ...

  5. 【Java基础】泛型的一些总结

    什么是泛型 泛型其实可以理解为一种广泛的类型,啥类型都型,当然,这种泛是指定义时可以广泛,但是使用时必须确定类型.也就是说,当不清楚未来使用哪种类型时,定义为泛型.可以支持泛型类,泛型接口,泛型方法, ...

  6. JBPM学习(五):流程变量

    1.启动流程实例 // 启动流程实例 @Test public void startProcessInstance() { // 使用指定key的最新版本的流程定义启动流程实例 ProcessInst ...

  7. 如何用Java进行3DES加密解

    原文地址: http://weavesky.com/2008/01/05/java-3des/ 最近一个合作商提出使用3DES交换数据,本来他们有现成的代码,可惜只有.net版本,我们的服务器都是Li ...

  8. 使用HttpClient进行http post/get方法的调用,以及使用dom4j解析xml

    import java.io.IOException; import java.util.List; import javax.servlet.ServletInputStream; import j ...

  9. 基于smack的xmpp packet 重写

    基于Smack 实现Notification数据包.smack的类中有一个org.jivesoftware.smack.packet.IQ只需对他重写即可,在做的时候其实可以简单一点的,如果你使用ti ...

  10. java 5 线程池

    import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Thr ...