using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2.第11章
{
public class Linq概述
{
/*mbus
列表和实体
本章的LINQ查询在一个包含1950~2008年一级方程式锦标赛的集合上进行。这些数据需要使用实体类和列表来准备
对于实体,定义类型Racer.Racer定义了几个属性和一个重载的ToString()方法,该方法以字符串格式显示赛手
这个类实现了IFormattable接口,以支持格式字符串的不同变体,这个类还实现了IComparatble接口
它根据LastName为一组赛手排序。为了执行更高级的查询,Racer类不仅包含单值属性,如Firstname和Lastname
Wins,Country和Starts,还包含多值属性,如Cars和Years.Years属性列出了赛手获得冠军的年份。一些赛手曾多次获得冠军
Cars属性用于列出赛手冠军的年份中使用的所有车型
*/
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2.第11章
{
/*Formulal类在GetChampions()方法中返回一组赛手。这个列表包含了1950~2008年之间所有一级方程式冠军*/
public static class Formulal
{
private static IList racers;
public static IList GetChampions()
{
if (racers == null)
{
racers = new List(40);
Racer rr = new Racer(
"Nino",
"Farina",
"Italy",
33,
5,
new int[] { 1950 },
new string[] { "Alfa Romeo" }
);
racers.Add(
rr
);
racers.Add(
new Racer("Alberto","Ascari","Italy",33,5,new int[] { 1950},new string[] { "Alfa Romeo"})
);
racers.Add(
new Racer("Juan Manuel","Fangio","Argentina",51,24,new int[] { 1951,1954,1955,1956,1957},
new string[] { "Alfa Romeo","Maserati","Mercedes","Ferrari"}
)
);
racers.Add(new Racer("Mike","Hawthorn","UK",45,3,new int[] { 1958},new string[] { "Ferrari"}));
racers.Add(new Racer("Phil","Hill","USA",48,3,new int[] { 1961},new string[] { "Ferrari"}));
racers.Add(new Racer("John","Surtees","UK",111,6,new int[] { 1964},new string[] { "Ferrari"}));
}
return racers;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2.第11章
{
public class CJT188_2004
{
//59200991
//FE FE FE FE 68 20 91 09 20 59 00 11 11 01 03 1F 90 12 82 16
//FE FE FE FE FE FE FE FE FE FE FE FE 68 25 91 09 20 59 00 11 11 81 2E 1F 90 12 00 00 00 00 05
//00 03 00 00 00 05 00 00 00 00 17 00 00 00 00 35 27 00 00 00 2C 61 14 00 74 14 00 46 54 00
//51 49 09 22 04 10 20 00 00 6D 16
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2.第11章
{
public class Team
{
public Team(string name, params int[] years)
{
this.Name = name;
this.Years = years;
}
private string Name { get; set; }
private int[] Years { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2.第5章
{
class DocumentManager
{
/*
DocumentManger现在可以处理任何实现了IDocument接口的类
在示例应用程序中,介绍了接口约束。泛型支持几种约束类型
约束 说明
where T : struct 对于结构约束 类型T必须是值类型
where T : class 类约束指定类型T必须是引用类型
where T:IFoo 指定类型T必须实现接口IFoo
where T:Foo 指定类型T必须派生自基类Foo
where T:new
*/
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2.第5章
{
class 泛型
{
/*
泛型
本章内容:
泛型概述
创建泛型类
泛型类的特性
泛型接口
泛型结构
泛型方法
.NET自从2.0版本开始就支持泛型 泛型不仅是C#编程语言的一部分 而且与程序集中的IL(Intermediate Language中间语言)
代码紧密继承 有了泛型 就可以独立于被包含类型的类和方法了 我们不必给不同的类型编写功能相同的许多方法和类
只创建一个方法或类即可
另一个减少代码的选项是使用Object类 但Object类不是类型安全的。泛型类使用泛型类型,并可以根据需要用特定的类型替换泛型类型
这就保证了类型安全性 如果某个类型不支持泛型类 编译器就会出现错误
泛型并不是一个全新的结构 其他语言中有类似的概念 例如 C++模板就与泛型相似 但是C++模板和.NET泛型之间有一个很大的区别
对于C++模板 再用特定的类型实例化模板时,需要模板的源代码 相反 泛型不仅是C#语言的一种结构 而且是CLR定义的 所以 即使泛型类
是在C#中定义的 也可以在Visual Basic中用一个特定的类型实例化该泛型
下面几节介绍泛型的优点和缺点,尤其是:
性能
类型安全性
二进制代码重用
代码的扩展
命名约定
5.1.1 性能
泛型的一个主要优点是性能。第10章介绍了System.Collections和System.Collections.Generic名称空间的泛型和非泛型集合类
对值类型使用非泛型集合类,在把值类型转换为引用类型和把引用类型转换为值类型时,需要进行装箱和拆箱操作
装箱和拆箱详见第7章,这里仅简要复习一下这些术语
值类型存储在栈上,引用类型存储在堆上。C#类是引用类型 结构是值类型。.NET很容易把值类型转换为引用类型,所以可以在需要对象(
对象是引用类型)的任意地方使用值类型。例如,int可以赋予一个对象。从值类型转换为引用类型成为装箱,如果方法需要把一个对象作为参数
同时传递一个值类型,装箱操作就会自动进行,另一方面,装箱的值类型可以使用拆箱操作转换为值类型,在拆箱时,需要使用类型强制转换运算符
下面的例子显示了System.Collections名称空间中的ArrayList类。ArrayList存储对象,Add()方法定义为需要把一个对象作为参数
所以要装箱一个整数类型,在读取ArrayList中的值时,要进行,把对象转换为整数类型,可以使用类型强制转换运算符把ArrayList集合
的第一个原酸赋予变量il,在访问int类型的变量i2的foreach语句中,也要使用类型强制转换运算符
var list = new ArrayList();
list.
/
public void Test()
{
var list = new ArrayList();
list.Add(44);//boxing - convert a value type to a reference type
int il = (int)list[0];//unboxing-convert a reference type to
foreach (int i2 in list)
{
Console.WriteLine(i2);//unboxing
}
}
/
装箱和拆箱操作很容易使用,但性能损失比较大,遍历许多项时尤其如此
System.Collections.Generic名称空间中的List类不使用对象,而是在使用时定义类型,在下面的例子中
List类的泛型类型定义为int,所以int类型在JIT编译器动态生成的类中使用
/
public void 装箱()
{
var list = new List();
list.Add(44);//no boxing - value types are stored in the List
int i1 = list[0];
foreach (int i2 in list)
{
Console.WriteLine(i2);
}
}
/泛型的另一个特性是类型安全。与ArrayList类一样,如果使用对象,就可以在集合中添加任意类型
下面例子在ArrayList类型的集合中添加一个整数、一个字符串和一个MyClass类型的对象/
/
5.3 泛型类的功能
在创建泛型类时,还需要一些其他C#关键字。例如,不能把null赋予泛型类型。此时,如下一节所述
可以使用default关键字。如果泛型类型不需要Object类的功能,但需要调用泛型类上的某些特定方法
就可以定义约束:
本节讨论如如下主题:
默认值
约束
继承
静态成员
首先介绍一个使用泛型文档管理器的示例。文档管理器用于从队列中读写文档。先创建一个新的控制台项目DocumentManager
并添加DocumentManager类。AddDocument()方法将一个文档添加到队列中
如果队列不为空,IsDocumentAvailable只读属性就返回true
*/
}
public class DocumentManager
{
private readonly Queue documentQueue = new Queue();
public void AddDocument(T doc)
{
lock (this)
{
documentQueue.Enqueue(doc);
}
}
public bool IsDocumentAvailable
{
get { return documentQueue.Count > 0; }
}
public T GetDocument()
{
T doc = default(T);
lock (this)
{
doc = documentQueue.Dequeue();
}
return doc;
}
/*要使用DocumentManager类显示文档,可以将类型T强制转换为IDocument接口,
已显示标题*/
public void DisplayAllDocuments()
{
foreach (T item in documentQueue)
{
Console.WriteLine(((IDocument)item).Title);
}
}
/*
default关键字根据上下文可以有多种含义。switch语句使用default定义默认情况
在泛型中,根据泛型类型是引用类型还是值类型,泛型default用于将泛型类型初始化为null或0
*/
}
}
/*5.3.1 默认值
现在给DocumentManager类添加一个GetDocument()方法。这个方法中,应把类型T指定为null
但是,不能把null赋予泛型类型。原因是泛型类型也可以实例化为值类型,而null只能用于引用类型
为了解决这个问题,可以使用default关键字。通过default关键字,将null赋予引用类型
将0赋予值类型
约束
如果泛型类需要调用泛型类型中的方法,就必须添加约束。对于DocumentManager,文档的所有标题应在DisplayAllDocuments()
方法中显示。Document类实现带有Title和Content属性的IDocument接口
*/
public interface IDocument
{
string Title { get; set; }
string Content { get; set; }
}
public class Document : IDocument
{
public Document()
{
}
public Document(string title,string content)
{
this.Title = title;
this.Content = content;
}
public string Title { get; set; }
public string Content { get; set; }
}
/*
问题是,如果类型T没有实现IDocument接口,这个类型强制转换就会导致一个运行异常。最好给
DocumentManager类定义一个约束:TDocument类型必须实现IDocument接口
为了在泛型类型的名称中指定该要求,将T改为TDocument.where子句指定了实现IDocument接口的要求
*/
public class DocumentManger where TDocument:IDocument
{
/这样就可以编写foreach语句,从而使类型TDocument包含属性Title.Visual Studio IntelliSense和编译器
都会提供这个支持/
private readonly Queue documentQueue = new Queue();
public void DisplayAllDocuments()
{
foreach (TDocument doc in documentQueue)
{
Console.WriteLine(doc.Title);
}
}
/在Main()方法中,用Document类型实例化DocumentManager类/
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2.第三章.Models
{
public class PhoneCustomer
{
public const string DayOfSendingBill = “Monday”;
public int CustomerID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
//struct PhoneCustomerStruct
//{
// public const string DayOfSendingBill = "Monday";
// public int CustomerID { get; set; }
// public string FirstName { get; set; }
// public string LastName { get; set; }
//}
/*
* 常量与类的关联方式同变量与类的关联方式。使用const关键字来声明常量 如果把它声明为public 就可以在类的外部访问它
* 事件是类的成阿云,在发生某些行为(如改变类的字段和属性或者进行了某种形式的用户交互操作),它可以让对象通知调用方
* 客户可以包含所谓"事件处理程序"的代码来响应事件
* 函数成员
*/
public class MyClassOperator
{
PhoneCustomer phoneCustomer = new PhoneCustomer();//works for a class
//PhoneCustomerStruct phoneCustomerStruct = new PhoneCustomerStruct();//works for a struct
public void Test()
{
phoneCustomer.FirstName = "Simon";
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2.第三章
{
class MainEntryPoint
{
static void Main1(string[] args)
{
//Try calling some static functions.
Console.WriteLine(“Pi is” + MathTest.GetPi());
int x = MathTest.GetSqureOf(5);
//Instantiate a MathTest object
MathTest math = new MathTest();//This is C#'s way of instantiating a reference type
//Call nonstatic methods
math.value = 30;
Console.WriteLine(
"Value file of math variable constatins" + math.value);
Console.WriteLine("Squre of 30 is" + math.GetSquare());
Console.ReadLine();
/*
Pi is3.14159
Value file of math variable constatins30
Squre of 30 is900
从代码中可以看出 MathTest类包含一个字段和一个方法 该字段包含一个数字 该方法计算该数字的平法
这个类还包含两个静态方法 一个返回Pi的值 另一个计算作为参数传入的数字的平方
这个类有一些功能并不是设计C#程序的好例子 例如 GetPi()通常作为cosnt字段来指定 而好的设计应使用目前还没有介绍
的概念
给方法传递参数
参数可以通过引用或通过值传递给方法 在变量通过引用传递给方法时,被调用的方法得到就是这个变量
所以在方法内部对变量进行的任何改变在方法退出后仍旧有效 如果变量通过值传送给方法
被调用的方法得到是变量的一个相同的副本 也就是数 在方法退出后 对变量的修改会丢失
对于复杂的数据类型 按引用传递的效率更高 因为在按值传递是 必须复制大量的数组
在C#中 除非特别说明 所有参数都通过值来传递 但是在理解引用类型的含义时需要注意
因为引用类型的变量只包含对象的引用 将要复制的正是这个引用而不是对象本身 所以对底层对象的修改会保留下来
相反 值类型的对象包含的是实际数据 所以传递给方法的数数据本身的副本 例如 int通过值传递给方法
对应方法对该Int的值所做的任何改变都没有改变原int对象的值。但如果把数组或其他引用类型(如类)
传递给方法 对应的方法就会使用该引用改变这个数组中的值 而新值会反射在原始数组对象上
下面的例子ParameterTest.cs说明了一点
*/
}
}
//Define a class named MathTest on which we will call a method
class MathTest
{
public int value { get; set; }
public int GetSquare()
{
return value * value;
}
public static int GetSqureOf(int x)
{
return x * x;
}
public static double GetPi()
{
return 3.14159;
}
}
}