【笔记】【LINQ编程技术】第一章 使用匿名类型

匿名类型使用关键字var。简而言之,匿名类型就是说你不用指定具体的类型。只要写上var即可,CSharp将计算出右侧表达式所定义的数据类型。然后CSharp编译器指定所定义的变量为该类型。类型被指定以后就相当于强类型,且由编译器在运行时进行类型检查。

请记住,你无需编写类型定义,因为CSharp会帮你计算出来。这一点很重要,因为在查询语言中,你所请求的以及所获取到的任何特定类型都是根据上下文(查询结果)来定义的。简单地说,查询结果可能会返回一个之前没有定义的类型。

1. 使用匿名类型时需要遵守的一些基本规则

  • 匿名类型必须有一个初始值,而且这个值不能是空值(null),因为类型是根据初始化器推断出来的
  • 匿名类型可以用于简单类型,也可以用于复杂类型。不过,用于定义简单类型时,其价值不大
  • 复合匿名类型需要有成员声明。比如说var joe = new {Name="Joe"}
  • 匿名类型支持只能感知技术
  • 匿名类型不能用于类的字段
  • 匿名类型可以在for训话中用作初始化器
  • 可以使用new关键字;数组的初始化器必须使用new关键字
  • 匿名类型可以用于数组
  • 所有匿名类型都派生于Object类型
  • 方法可以返回会匿名类型,不过需要转转成object,这破坏了强类型原则
  • 初始化匿名类型时可以加上方法,不过可能只有所谓的语言学家才会对这种做法产生兴趣

2. 使用匿名类型

2.1 定义简单匿名类型

var title = "LINQ Unleashed for C#";

2.2 使用数组初始化器语法

var fibonacci = new int[]{ 1, 1, 2, 3, 5, 8, 13, 21 };

2.3 创建复核匿名类型

var dena = new {First="Dena", Last="Swanson"};

2.4 给匿名类型添加方法

该技术定义了一个匿名委托,并将该匿名委托赋值给泛型类Func。在该示例中,Concat被定义为一个匿名委托,他接受两个字符串,将他们拼接到一起后再返回一个新的字符串。你可以将这个委托赋值给任何一个被定义为该Func实例(拥有三个子字符串类型的形参)的变量。最后,再在该匿名类型定义中将变量Concat赋值给一个成员声明器。

Func<string, string, string> Concat = delegate (string first, string last)
{
	return last + ", " + first;
};

var dena = new { First = "Dena", Last = "Swanson", Concat = Concat };
Console.WriteLine(dena.Concat(dena.First, dena.Last));

另外,匿名委托中亦可以使用反射机制获取信息:

Func<Type, Object, string> Concat = delegate (Type t, Object o)
{
	var info = t.GetProperties();
	return (string)info[1].GetValue(o, null) + ", " + (string)info[0].GetValue(o, null);
};
var dena = new { First="Dena", Last="Swanson", Concat=Concat };
Console.WriteLine(dena.Concat(dena.GetType(), dena));

2.5 在For循环中使用匿名类型索引

var fibonacci = new int[] { 1, 1, 2, 3, 5, 8, 13, 21 };
for (var i = 0; i < fibonacci.Length; i++)
	Console.WriteLine(fibonacci[i]);

2.6 在Foreach中使用匿名类型索引

var fibonacci = new int[] { 1, 1, 2, 3, 5, 8, 13, 21 };
foreach (var fibo in fibonacci)
	Console.WriteLine(fibo);

由于要在Foreach语句中迭代一个对象,唯一需要满足的条件就是该对象必须实现了IEnumerableIEnumberable。这也是可绑定性(比如GridView的数据绑定)的前提条件。以下的例子中,LINQ查询语句和拓展方法均返回了一个可枚举的对象。

var fibonacci = new int[] { 1, 1, 2, 3, 5, 8, 13, 21, 33, 54, 87 };

// uses Lambda expression with Where<int, bool> and Where is an extension method for IEnumerable
foreach (var fibo in fibonacci.Where(n => n % 3 == 0))
	Console.WriteLine(fibo);

// uses LINQ query
foreach (var fibo in from f in fibonacci where f % 3 == 0 select f)
	Console.WriteLine(fibo);

2.7 匿名类型和Using语句

using语句是try…finally的简洁表示。使用try…finallyusing的目的是,确保资源在using块退出或finally块结束之前被释放。通过调用Dispose(它要求在using语句中创建的那个对象必须实现了IDisposable)即可实现该目的。

string connectionString = "Data Source=BUTLER;Initial Catalog=AdventureWorks2000;Integrated Security=True";
using (var connection = new SqlConnection(connectionString))
{
	connection.Open();
	Console.WriteLine(connection.State);
}

2.8 从函数返回匿名类型

由于垃圾回收器会清理任何对象,因此,匿名各类型是可以从函数返回的。不过在定义范围之外,匿名类型指示一个object的实例而已。不幸的是,返回一个object将会使只能感知技术五熊,而且还会批灰匿名类型的强类型特性。虽然你可以通过反射来重新找出该匿名类型的功能,不过这也将使得这个本来很舒服的东西变得不那么舒服了。

static void Main(string[] args)
{
	var anon = GetAnonymous();
	var t = anon.GetType();
	Console.WriteLine(t.GetProperty("Stock").GetValue(anon, null));
}

public static object GetAnonymous()
{
	var stock = new { Stock = "MSFT", Price = "32.450" };
	return stock;
}

2.9 匿名类型的数据绑定

var quote1 = new { Stock = "DELL", Quote = GetQuote("DELL") };
var quote2 = new { Stock = "MSFT", Quote = GetQuote("MSFT") };
var quote3 = new { Stock = "GOOG", Quote = GetQuote("GOOG") };

var quotes = new object[] { quote1, quote2, quote3 };
DataList1.DataSource = quotes;
DataList1.DataBind();

2.10 测试匿名类型的相等性

匿名类型的相等性定义得非常严格。如果两个匿名类型有用相同的成员声明顺序、成员变量、成员投影类型以及成员名称,则认为他们是相等的。这种情况下是可以使用引用相等运算符的。如果想要测试成员的相等性,可以使用Equal方法。拥有相同的顺序/类型和名称/类型的匿名类型,器成员声明器的值也会产生相同的哈希值;而这些哈希值就是相等性测试的基础。

var audioBook1 = new { Artist = "Bob Dylan", Song = "I Shall Be Released" }; 	// Label1
var audioBook2 = new { Song = "I Shall Be Released", Artist = "Bob Dylan" }; 	// Label2
var songBook1 = new { Artist = "Bob Dylan", Song = "I Shall Be Released" };		// Label3
var songBook2 = new { Singer = "Bob Dylan", Song = "I Shall Be Released" };		// Label4

Console.WriteLine("====================变量类型====================");
Console.WriteLine("audioBook Type: " + audioBook1.GetType().ToString());
Console.WriteLine("audioBook Type: " + audioBook2.GetType().ToString());
Console.WriteLine("audioBook Type: " + songBook1.GetType().ToString());
Console.WriteLine("audioBook Type: " + songBook2.GetType().ToString());

Console.WriteLine("====================哈希代码====================");
Console.WriteLine("audioBook1 hash " + audioBook1.GetHashCode());
Console.WriteLine("audioBook2 hash " + audioBook2.GetHashCode());
Console.WriteLine("songBook1 hash  " + songBook1.GetHashCode());
Console.WriteLine("songBook2 hash  " + songBook2.GetHashCode());

Console.WriteLine(audioBook1 == songBook1);
Console.WriteLine(audioBook1.Equals(songBook1));
Console.WriteLine(audioBook1.Equals(songBook2));
Console.WriteLine(songBook1.Equals(songBook2));
Console.WriteLine(audioBook2.Equals(audioBook1));

2.11 通过LINQ查询使用匿名类型

var numbers = new int[] { 1, 2, 3, 4, 5, 6, 7 };
var all = from n in numbers orderby n descending select n;

foreach (var n in all)
	Console.WriteLine(n);

var songs = new string[] { "Let it be", "I shall be released" };
var newType = from song in songs select new { Title = song };

foreach (var s in newType)
	Console.WriteLine(s.Title);

2.12 泛型匿名方法简介

除了没有名字之外,匿名方法跟普通方法是一样的。它是通过定义委托来完成简单任务的一种方案,而完整的方法则意味着更多的代码量。匿名方法哈发展出了Lambda表达式。

static void Main(string[] args)
{
	Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);

	Console.CancelKeyPress += delegate
	{
		Console.WriteLine("Anonymous Cancel pressed");
	};
	
	Console.ReadLine();
}

static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
	Console.WriteLine("Cancel pressed");
}

2.13 使用匿名泛型方法

System.Func<long, long> Factorial = delegate (long n)
{
	if (n == 1) 
		return 1;
		
	long result = 1;
	
	for (int i = 2; i <= n; i++)
		result *= i;
		
	return result;
};

Console.WriteLine(Factorial(6));

2.14 实现内嵌的递归

上例中,使用For循环的执行计算的。下例中将该段代码改成使用递归的方式。最大的困难在于,这个命名委托载器定义完成之前是没有名字的。因此,在该匿名委托内部是不能使用这个名字的,不过你还是可以完成这个任务。

有一个叫StackFrame的类。StackFrame允许从调用栈中获取方法,也就是说,你可以利用这个类和反射来递归调用匿名委托。

Func<long, long> Factorial = delegate (long n)
{
   return n > 1 ? n * (long)(new StackTrace().GetFrame(0).GetMethod().Invoke(null, new object[] { n - 1 })) : n;
};

Console.WriteLine(Factorial(6));
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值