【C#4.0图解教程】笔记(第19章~第25章)

第19章 泛型
1.泛型概念
泛型提供了一种更准确地使用有一种以上的类型的代码的方式.
泛型允许我们声明类型参数化的代码,我们可以用不同的类型进行实例化.
泛型不是类型,而是类型的模板.
 
2.声明泛型
●在类名之后放置一组尖括号
●在尖括号中用逗号分隔的占位符字符串来表示希望提供的类型,这被叫做类型参数
●在泛型类声明的主体中使用类型参数来表示应该被替代的类型.
eg:声明与实例化
namespace ConsolePractice
{
    class SomeClass<T1, T2>//声明一个泛型,类型参数T1,T2,也不一定要用T,可以用任意字符.
    {
    }
 
    class Class2
    {
        static void Main()
        {
            var first = new SomeClass<shortint>();//构造的类型实例化
            var second = new SomeClass<intlong>();//构造的类型实例化
        }
    }
}
 
3.类型参数的约束
约束使用where子句列出
●每一个有约束的类型参数有自己的where子句
●如果形参有多个约束,它们在where子句中使用逗号分隔.
●where子句在类型参数列表的关闭尖括号之后列出
●where子句不使用逗号或其他符号分隔;
●where子句可以以任何次序列出.
●where是上下文关键字,所以可以在其他上下文中使用.
 
4.约束类型与次序
书上没实例,不太懂,详情百度
 
5.泛型方法
eg:声明和调用实例
namespace ConsolePractice
{
    class Simple
    {
        static public void ReverseAndPrint<T>(T[] arr)//声明一个泛型方法,作用:数组倒序
        {
            Array.Reverse(arr);
            foreach (T item in arr)
            {
                Console.Write("{0},", item.ToString());
            }
            Console.WriteLine();
        }
    }
 
    class Program
    {
        static void Main()
        {
            var intArray = new int[] { 3, 5, 7, 9, 11 };//var也可写成int[]
            var stringArray = new string[] { "first""second""third" };
            var doubleArray = new double[] { 3.567, 7.891, 2.345 };
 
 
            Simple.ReverseAndPrint<int>(intArray);//调用方法
            Simple.ReverseAndPrint(intArray);//由于编译器可以从方法参数中推断类型参数,我们可以省略类型参数和调用中的尖括号
 
 
            Simple.ReverseAndPrint<string>(stringArray);
            Simple.ReverseAndPrint(stringArray);
 
 
            Simple.ReverseAndPrint<double>(doubleArray);
            Simple.ReverseAndPrint(doubleArray);
 
            Console.ReadKey();
        }
    }
}
 
6.泛型结构
eg:实例说明一切
 
7.泛型委托
eg:没有返回值的实例
eg:有返回值的实例
 
8.泛型接口
eg:泛型接口实例
 
9泛型的协变和逆变
暂时没看,看不下
 
 
 
 
第20章 枚举数和迭代器
1.为什么数组可以用foreach迭代
为什么数组就可以使用foreach迭代呢?原因是数组可以提供一个叫做枚举数的对象.枚举数可以依次返回请求的数组的元素.
对于有枚举数的类型而言,必须有一个方法来获取它们,在.NET中获取一个对象枚举数的标准方法是调用对象的GetEnumerator方法.实现GetEnumerator方法的类型叫做可枚举类型.数组是可枚举类型.
 
2.枚举数类型
枚举数一共有3种:
●IEnumerator/IEnumerable接口——非泛型接口形式.
●IEnumerator<T>/IEnumerable<T>接口——泛型接口形式
●不使用接口形式.
 
3.使用IEnumerator接口
该接口包含三个函数成员:Current,MoveNext以及Reset.
Current返回序列中当前位置项的属性.
MoveNext是把枚举数位置前进到集合中下一项的方法,它返回布尔值,指示新的位置是有效位置或已经超过了序列的尾部.
Reset方法把位置重置为原始状态.
eg:
using System;
using System.Collections;
 
namespace ConsolePractice
{
    class Program
    {
        static void Main()
        {
            int[] MyArray = { 10, 11, 12, 13 };//创建数组
 
            IEnumerator IE = MyArray.GetEnumerator();//获取枚举数
            while (IE.MoveNext())//移到下一项
            {
                int i = (int)IE.Current;//获取当前项
                Console.WriteLine("{0}", i);//输出
            }
            Console.ReadKey();
        }
    }
}
 
4.声明IEnumerator的枚举数
要创建非泛型接口的枚举数类,必须声明实现IEnumerator接口的类.IEnumerator接口的特性如下:
●它是System.Collenctions命名空间的成员.
●它包含3个方法Current,MoveNext和Reset.
 
5.IEnumerable接口
该接口只有一个成员——GetEnumberator方法,它返回对象的枚举数.
 
6.IEnumerable和IEnumerator示例
using System;
using System.Collections;
 
namespace ConsolePractice
{
    class ColorEnumerator : IEnumerator//继承IEnumerator接口就必须实现MoveNext(),Reset()方法和Current属性
    {
        string[] Colors;
        int Position = -1;
 
        public ColorEnumerator(string[] theColors)//构造函数
        {
            Colors = new string[theColors.Length];
            for (int i = 0; i < theColors.Length; i++)
            {
                Colors[i] = theColors[i];
            }
        }
 
        public object Current
        {
            get
            {
                if (Position == -1)
                {
                    throw new InvalidOperationException();
                }
                if (Position == Colors.Length)
                {
                    throw new InvalidOperationException();
                }
                return Colors[Position];
            }
        }
 
        public bool MoveNext()
        {
            if (Position < Colors.Length - 1)
            {
                Position++;
                return true;
            }
            else
                return false;
        }
 
        public void Reset()
        {
            Position = -1;
        }
    }
 
    class MyColors : IEnumerable//继承了IEnumerable就必须实现GetEnumerator()方法.
    {
        string[] Colors = { "Red""Yellow""Blue" };
        public IEnumerator GetEnumerator()
        {
            return new ColorEnumerator(Colors);
        }
    }
 
    class Program
    {
        static void Main()
        {
            MyColors mc = new MyColors();
            foreach (string color in mc)
                Console.WriteLine(color);
            Console.ReadKey();
        }
    }
}
 
7.不实现接口的枚举数
 
8.泛型枚举接口
IEnumerable<T>和IEnumerator<T>
IEnumerator<T>接口
该接口另外两个接口继承——非泛型IEnumerator接口和IDisposable接口(IDisposable接口只有一个叫做Dispose的类型为void的无参方法,它可以用于释放由类占据的非托管资源),所以必须实现他们的成员
IEnumerable<T>接口
该泛型从IEnumerable继承,所以必须实现IEnumera接口的成员
 
9.迭代器
迭代器块有两个特殊语句
yield return语句执行了序列中返回的下一项
yield break语句指定在序列中没有更多项.
 
10.使用迭代器来创建枚举数
 
11.使用迭代器来创建可枚举类型
 
12.常见迭代器模式
 
13.产生多个可枚举类型和多个枚举数
P361~P363两个实例
 
 
 
 
第21章 介绍LINQ
1.匿名类型
这种形式的对象创建表达式由三部分组成:new关键字,类名或构造函数以及对象初始化器.
匿名类型只能和局部变量配合使用,不能用于类成员.
由于匿名类型没有名字,所以必须使用var关键词作为变量类型
eg:
 
2.查询方法和方法语法
查询方法:是声明形式的,看上去和SQL语句很相似,查询语法使用查询表达式形式书写.
方法语法:是命令形式的,它使用的是标准的方法调用.方法是一组叫做标准查询运算符的方法.
eg:
 
3.查询表达式的结构
from子句
form子句指定了要作为数据源使用的数据集合.
join子句
用于联结两个集合然后创建一个临时的对象集合.
let子句
let子句接受一个表达式的运算符并且把它赋值给一个需要在其他运算符中使用的标识符.
where子句
where子句根据之后的运算来去除不符合指定条件的项.
eg:
orderby子句
orderby子句接受一个表达式并根据表达式依次返回结果项.(排序)
select子句
可用于选择对象的某些字段,也可以用来创建匿名类型
eg:
group子句
group子句把select的对象根据一些标准进行分组.作为分组依据的项叫做键(key)
eg:
 
4.查询延续
eg:
using System;
using System.Linq;
 
namespace ConsolePractice
{
    class Program
    {
        public static void Main()
        {
            var groupA = new[] { 3, 4, 5, 6 };
            var groupB = new[] { 4, 5, 6, 7 };
 
            var someInts = from a in groupA
                           join b in groupB on a equals b
                           into groupAandB
                           from c in groupAandB//查询延续,将结果放入groupAaandB中
                           select c;
 
            foreach (var a in someInts)
                Console.Write("{0} ", a);
            Console.ReadKey();
        }
    }
}
 
5.标准查询运算符
标准查询运算符由一系列叫做API的方法组成.
System.Linq.Enumerable类声明了标准查询运算符方法.这些方法是扩展了IEnumerable<T>泛型的扩展方法.
由于运算符是扩展IEnumerable的扩展方法,所以它们必须满足下面语法条件
●必须声明为public或static
●必须在第一个参数前有this扩展指示器.
●必须把IEnumerable<T>作为第一个参数类型
eg:
using System;
using System.Linq;
using System.Collections;
 
namespace ConsolePractice
{
    class Program
    {
        public static void Main()
        {
            int[] intArray = new int[] { 3, 4, 5, 6, 7, 9 };
 
            var count1 = Enumerable.Count(intArray);//直接调用
            var firstnum1 = Enumerable.First(intArray);//直接调用
 
            var count2 = intArray.Count();//扩展方法调用(数组intArray作为被扩展的对象)
            var firstnum2 = intArray.First();//扩展方法调用
 
            Console.WriteLine("Count:{0},FirstNumber:{1}", count1, firstnum1);
            Console.WriteLine("Count:{0},FirstNumber:{1}", count2, firstnum1);
 
            Console.ReadKey();
        }
    }
}
 
6.委托参数
eg:这一节有点晕,找个适合重看吧
 
7.LINQ to XML
LINQ to XML API由很多表示XML树组件的类组成,其中最重要的三个类是:
XElement,XAttribute和XDocument.
除了XAttribute类,大多数用于创建XML树的类都从一个叫做XNode的类继承.
eg:创建,保存,加载,显示XML文档
 
8.XML树
补充:
Nodes方法:可以使用以类型作为参数的方法OfType(type)来指定返回某个类型的节点.
Elements方法:它是Nodes.OfType(XElement)()表达式的简写.该方法无参数时返回所有子XElements,使用单个name参数的Elements方法只返回具有这个名字的子XElements
Element方法:这个方法只获取当前节点的第一个子XElement.如果带参数,则获取第一个具有那个名字的子XElement.
eg:显示了Element和Elements方法:
 
9.XML的操作
eg:
 
10.使用XML属性
eg:添加,获取,移除,改变属性
using System;
using System.Xml.Linq;
 
namespace ConsolePractice
{
    class Program
    {
        public static void Main()
        {
            XDocument xd = new XDocument(
                new XElement("root",
                    new XAttribute("color","red"),//创建时添加属性
                    new XAttribute("size""large"),//创建时添加属性
                    new XElement("first")
                    )
                );
 
 
            Console.WriteLine(xd);//显示XML树
            Console.WriteLine();//空行
 
 
            XElement rt=xd.Element("root");//获取元素
 
            XAttribute color = rt.Attribute("color");//获取属性
            XAttribute size = rt.Attribute("size");//获取属性
 
            Console.WriteLine("Color is {0}", color.Value);//显示属性值
            Console.WriteLine("Size is {0}", size.Value);//显示属性值
            Console.WriteLine();//空行
 
 
            rt.SetAttributeValue("size""mediun");//改变属性值
            rt.SetAttributeValue("width","narrow");//添加属性,就是没有查找不到这个属性时,则添加这个属性
            Console.WriteLine(xd);//显示XML树
            Console.WriteLine();//空行
 
 
            rt.Attribute("color").Remove();//移除属性
            rt.SetAttributeValue("size"null);//移除属性,把某个属性设置为空就等于移除了.
            Console.WriteLine(xd);//显示XML树
 
            Console.ReadKey();
        }
    }
}
 
11.使用LINQ to XML的LINQ查询
eg:
饿死了......
 
 
 
 
第22章 同步与异步
再看吧
 
 
 
第23章 预处理指令
1.#define和#undef指令
#define指令声明一个编译符号
#undef指令取消定义一个编译符号
#define和#undef指令只能用在源文件的第一行,第一行!
 
2.条件编译
条件编译允许我们根据某个编译符号是否被定义标注一段代码被编译或跳过.
有4个指令可以用来指定条件编译:
#if
#else
#elif
#endif
 
3.诊断指令
诊断指令的字符串不需要被引号包围.
#error指令在#if结构中,因此只有符合#if指令的条件时才会生成消息.
#warning指令用于提醒程序员回头来清理这段代码.
 
4.行号指令
关键字#line
功能:
●改变由编译器警告和错误消息报告的出现行数;
●改变被编译器源文件的文件名;
●对交互式调试器隐藏一些行.
#line指令语法如下:
#line integer             //设置下一行值为整数的行的行号,integer表示行号 #line "filename"       //设置文件名 #line default            //重新保存实际的行号和文件名 #line hidden            //在断点调试器中隐藏代码 #line                         //停止在调试器中隐藏代码
 
5.区域指令
#region
#endregion
不解释了
 
6.#pragma warning指令
该指令允许我们关闭及重新开启警告消息
●.要关闭警告消息,可以使用disable加上逗号分隔的希望关闭的警告数列表的形式.
●.要重新开启警告消息,可以使用restore加上逗号分隔的希望关闭的警告数列表的形式.
eg:关闭了618和414的警告消息,开启了618的警告消息,若不带警告数字列表,则会应用于所有警告.
 
 
 
 
第24章 反射和特性
1.元数据和反射
●有关程序及其类型的数据被称为元数据,它们保存在程序的程序集中.
●程序在运行时,可以查看其它程序集或其本身的元数据.一个运行的程序查看本身的元数据或其他程序的元数据的行为叫做反射.
 
2.Type类
要使用反射,必须使用System.Reflection命名空间.
BCL声明了一个叫做Type的抽象类,它被设计用来包含类型的特性.
 
3.获取Type对象
object类型包含了一个方法叫做GetType方法,用于返回对实例Type对象的引用.
eg:
 
4.特性
特性是一种允许我们向程序的程序集增加元数据的语言结构,它用于保护程序结构信息的某种特殊类型的类.
●将应用了特性的程序结构叫做目标
●设计用来获取和使用元数据的程序被叫做特性的消费者
●.NET预定了很多特性,也可以自定义特性.
 
5.预定义的保留的特性
①Obsolete特性
该特性用于将程序标注为过期的并且在代码编译时显示有用的警告信息
eg:
 
②Conditional特性
该特性允许我们包括或排斥某个特定方法的所有调用.为方法声明引用Conditional特性并把编译符作为参数来使用.
●如果定义了编译符号,那么编译器会包含所有调用这个方法的代码,这和普通方法没有区别
●如果没有定义编译符号,则编译器会忽略代码中这个方法的所有调用.
eg:
 
6.预定义的特性
 
7.多个特性
可以为代码片段显示应用多个特性,有两种方式:等价的
 
8.特性目标
C#定义了10个标准的特性目标
 
9.声明自定义特性
P444~449没看,再看吧
 
 
 
 
第25章 其他主题
1.string类型的有用成员
 
2.使用StringBuilder类
该类可以动态,有效地产生字符串,并且避免创建许多副本.(string每一次修改都会产生副本,因为字符串是不可变,只能重建)
 
3.格式化数字字符串
语法如图:由索引号,对齐说明符和格式说明符组成
对齐说明符特性如下:
●可选的,用逗号来和索引号分离
●由一个正整数或负整数组成.整数部分表示字段使用字符最少数量,符号表示左对齐还是右对齐,正数表示右对齐,负数表示左对齐.
格式组件:分为两部分
●格式说明符:看下表
●精度说明符:可选,由1~2为数字组成,它的意义取决于格式说明符
eg:
 
4.把字符串解析为数据值.
所有预定义的简单类型都有一个叫做Parse的静态方法,它接受一个表示这个类型的字符串,并且把它转换为类型的实际值.
eg:
Parse方法的缺点是如果不能把string成功转换为目标类型的话会抛出一个异常.而TryParse方法可以避免这个问题.
TryParse方法接受两个参数并返回一个bool值
●第一个参数是希望转换的字符串.
●第二个参数是指向目标类型变量的引用的out参数.
●如果TryParse成功,返回true,否则返回false.
eg:
 
5.可空类型
●可以从任何值类型创建可空类型,包括预定义的简单类型.
●不能从引用类型或其他类型创建可空类型
●不能在代码中显示声明可空类型,只能说明可空类型的变量.
可空类型的几个重要的属性:
●HasValue属性是bool类型,并且指示值是否有效.
●value属性是和基础类型相同的类型,并且返回变量的值
eg:
使用空接合运算符
空接合运算符允许可空类型变量为null时返回一个值给表达式.
●第一个操作数可空类型的变量
●第二个是相同基础类型的不可空值.
●如果第一个操作数运算符后为null,那么第二个操作数就会被返回作为运算符结果.
eg:
 
6.可空用户自定义类型
可空用户自定义类型不会直接暴露基础类型的任何成员,只通过可空类型的Value属性暴露.
eg:看图,基础类型成员不可以被直接访问的.
 
 
posted @ 2013-09-14 15:15  漂移青春  阅读(244)  评论(0编辑  收藏  举报