C#学习笔记8
1.泛型的约束:
(1)接口约束;
(2)基类约束,基类约束必须放在第一(假如有多个约束);
(3)struct/class约束;
(4)多个参数类型的约束,每个类型参数都要用where关键字;
(5)构造器约束,只能是无参构造器,如new();
(6)约束可以由派生类继承,但必须在派生类中显式地指定这些约束;
(7)泛型方法的约束设置与泛型类的约束设置,是一样的;
2.协变性与逆变性:在泛型中,将一个较具体的类型赋给一个较泛化的类型,即是协变。将一个较泛化的类型赋给一个较具体的类型,即是逆变。
协变:在C#4.0中使用out类型参数修饰符允许协变性,该out修饰的类型参数,会导致该类型参数只能用于成员的返回与属性的取值方法,永远不用于输入参数或者属性的赋值方法。
逆变:在C#4.0中使用in类型参数修饰符允许逆变性,该in修饰的类型参数,会导致该类型参数只能用于成员的输入(输入参数)与属性的设置方法。
如Contact类继承自PdaItem,若对泛型接口(IConvertible<in T1,out T2>)进行了协变与逆变的设置,就可以成功地从一个IConvertible<PdaItem,Contact>转换成一个IConvertible<Contact,PdaItem>。
综上所述:协出逆进。
3.数组本身是支持协变与逆变,如PdaItem[] pdaItems=new Contact[]{},Contact[] pdaItems=(Contact)new PdaItem[]{}。
4.委托概述:长期以来经验丰富的C、C++程序员利用方法指针,将可执行的步骤(方法)作为参数传递给另一个方法。C#使用委托来提供相同的功能,它将方法作为对象封装起来,允许在运行时间接绑定一个方法的调用,可查看DelegateSample类的代码。
5.委托的定义:C#将所有委托的定义成间接派生于System.Delegate,其继承层次为Object -> Delegate ->MulticastDelegate -> 自定义委托。当然我们使用关键delegate声明,其在编译后生成的CIL代码,就是自动继承上面的结构,因此我们不能手动显式继承委托。在委托实例化中,从C@2.0开始可以不使用new来手工创建,直接赋值相同的签名方法即可,编译器会在编译过程中会自动根据委托推断,自动添加new创建,以及把方法名称作为委托参数传递也是一样,
6.系统自定义的委托:在.net3.5(C#3.0)中加入了Action与Func这个两个泛型委托,前者是没有返回值的委托,后者是有返回值的委托,在.Net4.0(C#4.0)中又在这些泛型委托中加入了in(逆变)/out(协变)的功能。这些委托的定义省略了我们手工进行自定义委托的情况,因为这些泛型委托都涵盖了我们可能遇到的所有使用情况。(除非你要定义一个有特殊含义的委托名称)。
7.委托使用可变性,即委托类型参数的可变性(协变与逆变),可查看DelegateSample.CovariantAndContravariant()方法的代码。
8.Lambda表达式:Lambda表达式是匿名函数的简洁表达形式,Lambda表达式包含语句Lambda与表达式Lambda,前者可以含有多个语句的语句块(一般只使用两三条语句),后者只有一句表达式。
9.使用Lambda表达式注意事项:
(1)Lambda表达式本身是无类型,只有赋值给一个委托,Lambda表达式就表现为有一个类型,就是该方法签名的委托。
(2)因Lambda表达式是无类型的,所以也就不能赋值给隐式类型的局部变量。
(3)如果目的地在Lambda表达式的外部,C#就不允许在匿名函数内部使用跳转语句(break、goto、continue),类似的,不能从Lambda表达式外部跳入Lambda表达式内部。
(4)对于在Lambda表达式内部引入的变量,其作用域仅限于Lambda表达式主体。
(5)编译器的程序执行流程分析机制检测不到在Lambda表达式内部初始化局部变量的情况。
以上的注意事项的代码实例,可以查看DelegateSample.NoticeMatter()方法。
10.Lambda表达式并非CLR内部的固有构造,它们的实现是由C#编译器在编译时生成的,编译器会自动把Lambda表达式生成为一个当前类的内部方法(静态或实例方法),其方法名是编译器自动处理(其一般含有anonymous等字眼的描述)。
11.在匿名函数中使用外部局部变量,编译器会把这些外部变量生成为当前类的嵌套类(sealed闭包)的公共字段,其嵌套类中含有公共字段与对应的匿名名称方法,因此这些局部变量变成了嵌套的成员,其生命周期也就被延长了。通过查看ILdasm(中间语言反编译,能够查看类库编译后的中间语言,VS工具自带)。也可查看DelegateSample.AscendingAndTimeOfCompiler()与_LocalDisplayClass_00001嵌套类。
12.表达式树:“解释”是C#引入表达式树这一概念的重要动机,如果一种Lambda表达式代表的是与表达式有关的数据,而不是编译好的代码(匿名函数与委托),这种Lambda表达式就是“表达式树”。由于表达式树代表的是数据而非编译好的代码,所以可以把数据转换成一种替代格式。
例如,可以把它从表达式数据转换成在数据库中执行的SQL代码。如IQueryable接口中含有表达式树类型、查询供应者、查询返回的类型,只要实现该接口就能对特定的数据源进行查询操作,期内包含需要自定义解析表达式树的指令。所有表达式树的类型(如ParameterExpression、BinaryExpression、MethodCallExpression),都是从Expression继承。
13.Lambda表达式和表达式树的比较:无论是用于委托的Lambda表达式,还是用于表达式树的Lambda表达式都会被编译,而且在这两种情况下,表达式的语法都会在编译时进行完整的语义分析验证。但是,两者的区别在于,Lambda表达式在CIL中遍编译成委托,而表达式树被编译成System.Linq.Expressions.Expression类型的一个数据结构。可查看AnalysisExpression类的代码,以及Output()方法输出的数据内容。
14.一个表达式树是由零个或者多个其他表达式树构成的,被包含的表达式树存储在Expression的Body属性中。通常,语句Lambda和表达式Lambda可以互换使用,然而,不能将语句Lambda转换成“表达式树”,只能使用表达式Lambda语法来表示“表达式树”。
public class DelegateSample
{
//冒泡排序,基本排序处理
public static void BubbleSort<TSource>(TSource[] items, Func<TSource, TSource, bool> predicate) where TSource : IComparable<TSource>, IEquatable<TSource>
{
if (items == null || items.Length < )
{
return;
}
TSource tempItem;
/*第一种算法,定点比较
for (int i = 0; i < items.Length; i++)
{
for (int j = i; j < items.Length; j++)
{
if (predicate(items[i], items[j]))
{
tempItem = items[i];
items[i] = items[j];
items[j] = tempItem;
}
}
}*/
//第二种算法,逐一比较
for (int i = items.Length - ; i >= ; i--)
{
for (int j = ; j <= i; j++)
{
if (predicate(items[j - ], items[j]))
{
tempItem = items[j - ];
items[j - ] = items[j];
items[j] = tempItem;
}
}
}
} public static void Ascending()
{
int[] items = new int[] { , , , , , };
Console.WriteLine("升序前");
foreach (var item in items)
{
Console.Write("{0}\t", item);
}
BubbleSort(items, (first, second) => first > second);
Console.WriteLine("\n升序后");
foreach (var item in items)
{
Console.Write("{0}\t", item);
}
} public static void Descending()
{
int[] items = new int[] { , , , , , };
Console.WriteLine("降序前");
foreach (var item in items)
{
Console.Write("{0}\t", item);
}
BubbleSort(items, (first, second) => first < second);
Console.WriteLine("\n降序后");
foreach (var item in items)
{
Console.Write("{0}\t", item);
}
}
//按字母排序
public static void AlphabeticalGreaterThan()
{
int[] items = new int[] { , , , , , };
Console.WriteLine("排序前");
foreach (var item in items)
{
Console.Write("{0}\t", item);
}
BubbleSort(items, (first, second) =>
{
int comparison = first.ToString().CompareTo(second.ToString());
return comparison > ;
});
Console.WriteLine("\n排序后");
foreach (var item in items)
{
Console.Write("{0}\t", item);
}
}
//委托的协变与逆变
public static void CovariantAndContravariant()
{
//逆变
Action<object> broadAction = delegate (object data) { Console.WriteLine(data); };
Action<string> narrowAction = broadAction; //协变
Func<string> narrowFunction = () => Console.ReadLine();
Func<object> broadFunction = narrowFunction; //协变与逆变
Func<object, string> func1 = (data) => data.ToString();
Func<string, object> func2 = func1;
}
//Lambda表达式注意事项
public static void NoticeMatter()
{
//错误:控制权不能离开Lambda表达式的主体。
/*string[] args;
Func<string> expression;
switch (args[0])
{
case "/File":
expression = () =>
{
if (!File.Exists(args[1]))
{
break;
}
//...
return args[1];
};
//...
}*/ //不能在Lambda表达式内部进行初始化局部变量。
/*int number;
Func<string, bool> expression = text => int.TryParse(text, out number);
if (expression("1"))
{
//错误:使用未赋值的局部变量
Console.WriteLine(number);
} int number:
Func<int, bool> isFortyTwo = x => 42 == (number = x);
if (isFortyTwo(42))
{
//错误:使用未赋值的局部变量
Console.WriteLine(number);
}*/
} //升序,并记录其比较的次数,编译前
public static void AscendingAndTime()
{
int comparisonCount = ;
int[] items = new int[] { , , , , , };
Console.WriteLine("升序前");
foreach (var item in items)
{
Console.Write("{0}\t", item);
}
BubbleSort(items, (first, second) =>
{
comparisonCount++;
return first > second;
});
Console.WriteLine("\n升序后");
foreach (var item in items)
{
Console.Write("{0}\t", item);
}
Console.WriteLine("\n比较的次数 {0}", comparisonCount);
} //升序,并记录其比较的次数,编译后
public static void AscendingAndTimeOfCompiler()
{
_LocalDisplayClass_00001 locals = new _LocalDisplayClass_00001();
locals.comparisonCount = ;
int[] items = new int[] { , , , , , };
Console.WriteLine("升序前");
foreach (var item in items)
{
Console.Write("{0}\t", item);
}
BubbleSort(items, locals._AnonymousMethod_000000);
Console.WriteLine("\n升序后");
foreach (var item in items)
{
Console.Write("{0}\t", item);
}
Console.WriteLine("\n比较的次数 {0}", locals.comparisonCount);
} private sealed class _LocalDisplayClass_00001
{
public int comparisonCount; public bool _AnonymousMethod_000000(int first, int second)
{
comparisonCount++;
return first > second;
}
}
} public class AnalysisExpression
{
//输出表达式树的数据结构
public void Output()
{
Expression<Func<int, int, bool>> expression = (x, y) => x > y;
Console.WriteLine("------------{0}------------", expression);
PrintNode(expression.Body, );
Console.WriteLine("\n");
expression = (x, y) => x * y > x + y;
Console.WriteLine("------------{0}------------", expression);
PrintNode(expression.Body, );
Console.WriteLine("\n");
}
//打印表达式树节点,一般表达式树
private void PrintNode(Expression expression, int indent)
{
if (expression is BinaryExpression)
{
PrintNode(expression as BinaryExpression, indent);
}
else
{
PrintSingle(expression, indent);
}
}
//打印表达式树节点,二元表达式树
private void PrintNode(BinaryExpression expression, int indent)
{
//表达式树是一个数据集合,而通过遍历数据,就可以将数据转换成另一种格式。此处将数据直接转换成对应的文本,然而,具体如何对数据进行解释,完全是开发者自己决定。
PrintNode(expression.Left, indent + );
PrintSingle(expression, indent);
PrintNode(expression.Right, indent + );
}
//打印单个表达式树节点内容
private void PrintSingle(Expression expression, int indent)
{
Console.WriteLine("{0," + indent * + "}{1}", "", NodeToString(expression));
}
//节点转到字符
private string NodeToString(Expression expression)
{
string content;
switch (expression.NodeType)
{
case ExpressionType.Multiply:
content = "*";
break;
case ExpressionType.Add:
content = "+";
break;
case ExpressionType.Divide:
content = "/";
break;
case ExpressionType.Subtract:
content = "-";
break;
case ExpressionType.GreaterThan:
content = ">";
break;
case ExpressionType.LessThan:
content = "<";
break;
default:
content = string.Format("{0}({1})", expression, expression.NodeType);
break;
}
return content;
}
}
---------------------以上内容根据《C#本质论 第三版》进行整理
C#学习笔记8的更多相关文章
- js学习笔记:webpack基础入门(一)
之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...
- PHP-自定义模板-学习笔记
1. 开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2. 整体架构图 ...
- PHP-会员登录与注册例子解析-学习笔记
1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...
- 2014年暑假c#学习笔记目录
2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...
- JAVA GUI编程学习笔记目录
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
- seaJs学习笔记2 – seaJs组建库的使用
原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...
- CSS学习笔记
CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...
- HTML学习笔记
HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...
- DirectX Graphics Infrastructure(DXGI):最佳范例 学习笔记
今天要学习的这篇文章写的算是比较早的了,大概在DX11时代就写好了,当时龙书11版看得很潦草,并没有注意这篇文章,现在看12,觉得是跳不过去的一篇文章,地址如下: https://msdn.micro ...
- ucos实时操作系统学习笔记——任务间通信(消息)
ucos另一种任务间通信的机制是消息(mbox),个人感觉是它是queue中只有一个信息的特殊情况,从代码中可以很清楚的看到,因为之前有关于queue的学习笔记,所以一并讲一下mbox.为什么有了qu ...
随机推荐
- Java中的Random()函数-----转载
Java中的Random()函数 (2013-01-24 21:01:04) 转载▼ 标签: java random 随机函数 杂谈 分类: Java 今天在做Java练习的时候注意到了Java里面的 ...
- 12、OpenCV Python 图像梯度
__author__ = "WSX" import cv2 as cv import numpy as np def lapalian_demo(image): #拉普拉斯算子 # ...
- 关于logging的那些坑
python的logging日志记录模块非常强大,使用也很简单,但是特别容易出各种意外状况,打印各种出乎意料的log.最近对logging的一些原理进行了学习,再此做个记录,以备忘. 首先全面的了解一 ...
- JavaWeb学习笔记(四)—— response
一.response概述 response是Servlet.service方法的一个参数,类型为javax.servlet.http.HttpServletResponse.在客户端发出每个请求时,服 ...
- thinkphp3.2.3 批量包含文件
自己瞎写的...凑合看吧...核心就是用正则 表达式 或者 字符串 str_replace 进行 替换....... /** * 批量包含---,不能递归包含!!! 请不要在目标目录 包含 文件夹,因 ...
- POJ_1456 Supermarket 【并查集/贪心】
一.题面 POJ1456 二.分析 1.贪心策略:先保证从利润最大的开始判断,然后开一个标记时间是否能访问的数组,时间尽量从最大的时间开始选择,这样能够保证后面时间小的还能够卖. 2.并查集:并查集直 ...
- Hadoop基础入门
一.hadoop是什么? (1)Hadoop是一个开源的框架,可编写和运行分布式应用处理大规模数据,是专为离线和大规模数据分析而设计的,并不适合那种对几个记录随机读写的在线事务处理模式.Hadoop= ...
- jQuery随笔-自定义属性获取+tooltip
1.Jquery自定义属性获取 1) 通过自定义属性值获取document console.log($('[data-id='+item_id+']',listWrap)); $('[data-id= ...
- iView 初识
iView和element-UI在table这块有有相似之处,但是与layui有不同的地方 在data数据这里有明显的不同,在iView中data数组下每个元素对象对应一行的数据:而layui中,da ...
- 文献综述六:基于JS 技术的电子商品管理系统设计及实现
一.基本信息 标题:基于JS 技术的电子商品管理系统设计及实现 时间:2017 出版源:无线互联科技 文件分类:js技术的研究 二.研究背景 主要对Js下电商管理系统的设计及实现进行了探讨,利用软件工 ...