By Mony Hamza

摘至http://www.codeproject.com

Introduction

In the previous article, I illustrated some of the C# 3.0 new language and compiler features. I'll illustrate the rest of the features in this second part.

  1. Implicitly Typed Local Variables and Arrays
  2. Object Initializers
  3. Collection Initializers
  4. Extension Methods
  5. Anonymous Types
  6. Lambda Expressions
  7. Query Keywords
  8. Auto-Implemented Properties
  9. Partial Method Definitions

In this article, I will define the last five features and provide code samples.

Anonymous Types

The C# compiler enables you to create a new type at runtime which is not available at the source code level. It encapsulates a set of read-only properties into a single object without having to first explicitly define a type. The type of the properties is inferred by the compiler which can create an anonymous type by using the properties in an object initializer.

For example, consider the following declaration:

var person = new { Name = "Mony Hamza", SSN = "12345678" };

Here, the compiler automatically creates an anonymous type and infers the types of the properties from the object initializer. It also creates the private fields associated with these properties and the necessary set and get accessors. When the object is instantiated, the properties are set to the values specified in the object initializer.

Here is an example for declaring an anonymous type and displaying its content:

class MyClass

{

static void Main(string[] args)

{

// Declare an anonymous type:

var obj1 = new { Name = "Mony Hamza", SSN ="12345678" };

// Display the contents:

Console.WriteLine("Name: {0}\nSSN: {1}", obj1.Name,obj1.SSN);

Console.ReadLine();

}

}

Output:

Name: Mony Hamza

SSN: 12345678

I've received a question about why to use "implicitly typed variables". If you are to use an anonymous variable, then this variable must be initialized using the keyword var. We also have to consider the following notes about Anonymous types:

  • Anonymous types are reference types that derive directly from object. From the perspective of the common language runtime, an anonymous type is no different from any other reference types.
  • If two or more anonymous types have the same number and type of properties in the same order, the compiler treats them as the same type and they share the same compiler-generated type information.
  • An anonymous type has method scope. To pass an anonymous type, or a collection that contains anonymous types, outside a method boundary, you must first cast the type to object. However, this defeats the strong typing of the anonymous type. If you must store your query results or pass them outside the method boundary, consider using an ordinary named struct or class instead of an anonymous type.
  • Anonymous types cannot contain unsafe types as properties.
  • Because the Equals and GetHashCode methods on anonymous types are defined in terms of the Equals and GetHashcode of the properties, two instances of the same anonymous type are equal only if all their properties are equal.

Lambda Expressions

Lambda expressions provide a concise syntax for writing anonymous methods that can contain expressions and statements, and can be used to create delegates. All lambda expressions use the lambda operator =>, which is read as "goes to". The left side of the lambda operator specifies the input parameters (if any) and the right side holds the expression or statement block. The lambda expression x => x * x is read "x goes to x times x."

Using Anonymous Methods in C# 2.0

public delegate int MyDelegate(int n);

class AnonymouseMethods

{

static void Main()

{

// Anonymous method that returns the argument multiplied by 10:

MyDelegate delegObject1 = new MyDelegate(

delegate(int n) { return n * 10; }

);

// Display the result:

Console.WriteLine("The value is: {0}", delegObject1(5));

}

}

Using Lambda Expressions in C# 3.0

public delegate int MyDelegate(int n);

class LambdaExpresion

{

static void Main()

{

// Anonymous method that returns the argument multiplied by 10:

MyDelegate Obj1= new MyDelegate(

delegate(int n) { return n * 10; }

);

// Display the result:

Console.WriteLine("The value using an anonymous method is: {0}",

Obj1(5));

// Using lambda expression to do the same job:

MyDelegate Obj2 = (int n) => n * 10;

// or:

// MyDelegate Obj2 = n => n * 10;

// Display the result:

Console.WriteLine("The value using a lambda expression is: {0}",

Obj2(5));

Console.ReadLine();

}

}

Output:

The value using an anonymous method is: 50

The value using a lambda expression is: 50

We also can use more than one parameter in a lambda expression:

public delegate int MyDelegate(int m, int n);

MyDelegate myDelegate = (x, y) => x * y;

Console.WriteLine("The product is: {0}", myDelegate(5, 4));

More Examples

The following example shows you how to select the number which when divided by two has a remainder of 1.

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

int oddNumbers = numbers.Count(n => n % 2 == 1);

The following examples illustrate how to select the strings which starts with the letter M:

List < string > Names=new List < string >{"Mony","John","Liza"};

List < string > Filterd=Names.FindAll(name =>name.StartsWith("M"));

foreach(string i in Filterd)

{

Console.WriteLine(i);

}

Query Keywords

Keywords:

  1. from clause
  2. where clause
  3. select clause
  4. group clause
  5. into
  6. orderby clause
  7. join clause (Inner join, Group join, Left outer join)
  8. let clause

To understand Query expressions well, examples are the perfect choice.

The following example illustrates how to select numbers less than 5 and when divided by two have a remainder of 0.

static void Main()

{

// A simple data source.

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

// Create the query.

// lowNums is an IEnumerable < int >

var lowNums = from num in numbers

where num < 5 && num % 2 == 0

select num;

// Execute the query.

foreach (int i in lowNums)

{

Console.Write(i + " ");

}

}

The following example is from MSDN which will select all the students and their scores greater than 90, in order to access the inner list of scores. We use compound from clauses.

Collapse

public class Student

{

public string LastName { get; set; }

public List < int > Scores {get; set;}

}

static void Main()

{

// Use a collection initializer to create the data source. Note that

// each element in the list contains an inner sequence of scores.

List < Student> students = new List < Student>

{

new Student {LastName="Omelchenko", Scores= new List < int> {97, 72, 81, 60}},

new Student {LastName="O'Donnell", Scores= new List < int> {75, 84, 91, 39}},

new Student {LastName="Mortensen", Scores= new List < int> {88, 94, 65, 85}},

new Student {LastName="Garcia", Scores= new List < int> {97, 89, 85, 82}},

new Student {LastName="Beebe", Scores= new List < int> {35, 72, 91, 70}}

};

// Use a compound from to access the inner sequence within each element.

// Note the similarity to a nested foreach statement.

var scoreQuery = from student in students

from score in student.Scores

where score > 90

select new { Last = student.LastName, score };

// Execute the queries.

Console.WriteLine("scoreQuery:");

foreach (var student in scoreQuery)

{

Console.WriteLine("{0} Score: {1}", student.Last, student.score);

}

// Keep the console window open in debug mode.

Console.WriteLine("Press any key to exit.");

Console.ReadKey();

}

Output:

scoreQuery:

Omelchenko Score: 97

O'Donnell Score: 91

Mortensen Score: 94

Garcia Score: 97

Beebe Score: 91

Perform Joins (this example is also from MSDN which shows how to perform cross join with and without conditions).

Collapse

static void Main()

{

char[] upperCase = { 'A', 'B', 'C'};

char[] lowerCase = { 'x', 'y', 'z'};

var joinQuery1 =

from upper in upperCase

from lower in lowerCase

select new { upper, lower};

var joinQuery2 =

from lower in lowerCase

where lower != 'x'

from upper in upperCase

select new { lower, upper };

// Execute the queries.

Console.WriteLine("Cross join:");

foreach (var pair in joinQuery1)

{

Console.WriteLine("{0} is matched to {1}", pair.upper, pair.lower);

}

Console.WriteLine("Filtered non-equijoin:");

foreach (var pair in joinQuery2)

{

Console.WriteLine("{0} is matched to {1}", pair.lower, pair.upper);

}

// Keep the console window open in debug mode.

Console.WriteLine("Press any key to exit.");

Console.ReadKey();

}

Output:

Cross join:

A is matched to x

A is matched to y

A is matched to z

B is matched to x

B is matched to y

B is matched to z

C is matched to x

C is matched to y

C is matched to z

Filtered non-equijoin:

y is matched to A

y is matched to B

y is matched to C

z is matched to A

z is matched to B

z is matched to C

In the first query expression it selects the Upper, Lower so it matches each upper letter with all the lower ones. However, in the second filter example, it selects Lower, Upper so that it matches each lower letter with all the upper ones.

Using Group By

The group clause returns a sequence of IGrouping Of (TKey, TElement)) objects that contain zero or more items that match the key value for the group.

The following example will make it clear:

static void Main()

{

string[] Names = { "Mony", "Hamza", "Marica", "John", "Adam", "Olivia" };

var NameGroups =

from name in Names

group name by name[0];

// Execute the query.

foreach (var name in NameGroups)

{

Console.WriteLine("Names that start with the letter '{0}':", name.Key);

foreach (var name in NameGroups)

{

Console.WriteLine(name);

}

}

}

Output:

Names that start with the letter 'M':

Mony

Marica

Names that start with the letter 'H':

Hamza

Names that start with the letter 'J':

John

Names that start with the letter 'A':

Adam

Names that start with the letter 'O':

Olivia

Now let's add a little modification to the query in the previous example:

var NameGroups =

from name in Names

group name by name[0];

orderby name[0]

The result will be:

Names that start with the letter 'A':

Adam

Names that start with the letter 'H':

Hamza

Names that start with the letter 'J':

John

Names that start with the letter 'M':

Mony

Names that start with the letter 'O':

Olivia

Using into

It can be used to create a temporary identifier to store the results of a group, join or select clause into a new identifier. This identifier can itself be a generator for additional query commands.

//MSDN example

static void Main()

{

// Create a data source.

string[] words = { "apples", "blueberries", "oranges", "bananas", "apricots"};

// Create the query.

var wordGroups1 =

from w in words

group w by w[0] into fruitGroup

where fruitGroup.Count() >= 2

select new { FirstLetter = fruitGroup.Key,

Words = fruitGroup.Count() };

// Execute the query. Note that we only iterate over the groups,

// not the items in each group

foreach (var item in wordGroups1)

{

Console.WriteLine(" {0} has {1} elements.", item.FirstLetter, item.Words);

}

// Keep the console window open in debug mode

Console.WriteLine("Press any key to exit.");

Console.ReadKey();

}

Output:

a has 2 elements.

b has 2 elements.

Join

Inner Join

Collapse

namespace Joins

{

public class Department

{

public int ID{get; set;}

public string Name{get; set;}

}

public class Employee

{

public int ID{get; set;}

public string Name{get; set;}

public int DeptID{get; set;}

}

public void ManageJoin()

{

List < Department > Departments=new List < Department >

{new Department{ID=1, Name="Sales"},new Department

{ID=2,Name="Marketing"}};

List < Employees > Employees=new List < Employee >

{new Employee {ID=1,Name="Mony",DeptID=1},

new Employee{ID=2,Name="Tom",DeptID=2}};

//Inner Join

var innerJoinQuery = from employee in Employees

join dept in Department on employee.DeptID equals dept.ID

select new { EmployeeName = employee.Name,

DeptName = dept.Name };

}

}

The previous example will return each employee name and the department name.

Group Join

A join clause with an into expression is called a group join.

Left Outer Join

In a left outer join, all the elements in the left source sequence are returned, even if no matching elements are in the right sequence. To perform a left outer join, use the DefaultIfEmpty method in combination with a group join.

Let's modify the previous example to apply Left Outer Join:

var LeftouterJoinQuery = from employee in Employees

join dept in Department on employee.DeptID equals dept.ID

select new { EmployeeName = employee.Name,

DeptName = dept.Name } into empgroup

select empgroup.DefaultIfEmpty(new

{ EmployeeName = employee.Name, DeptName =

"No Department"});

Now it selects all the employees including those who are not attached to department yet.

Auto-Implemented Properties

You can use Auto Implemented Properties when no Additional logic is required, but you have to declare both a get and a set accessor.

//Auto Implemented Properties are used in the previous example, you can check it.

Partial Method Definitions

A partial class or struct may contain a partial method. One part of the class contains the signature of the method. An optional implementation may be defined in the same part or another part. If the implementation is not supplied, then the method and all calls to the method are removed at compile time.

Hope that I succeeded in making the C# 3.0 features quite clear.

Waiting for your feedback.

转载于:https://www.cnblogs.com/mm8413/archive/2008/01/31/1059770.html

C# 3.0 New Language Features (Part 2)相关推荐

  1. C# 3.0 New Language Features (Part 1)

    By Mony Hamza 摘至http://www.codeproject.com Introduction Well, in this article I'll illustrate some o ...

  2. TypeScript Essential Notes 2 - ES6 Language Features

    syntactic suguar 语法糖 Default parameters Template strings use backtick symbol backtick 反引号 bracket 大括 ...

  3. WARNING: One of the plugins you are using supports Java 8 language features. To try the support buil

    从github上下载一个项目导入到Android studio3.2.0上以后,发现报错:WARNING: One of the plugins you are using supports Java ...

  4. vscode 一直显示Load project: XXXX,保存时提示“从 “‘Vetur‘, ‘Vue Language Features (Volar)‘“ (configure)中获取代码操作”

    问题现象: vscode打开项目之后一直在底部提示一个通知:Load project: 当前项目,如下图所示: 在保存时提示:正在保存"Add.vue": 从 "'Vet ...

  5. 升级 GCC 支持C++11 或 configure: error: *** A compiler with support for C++11 language features is requir

    升级 GCC 支持C++11 或 configure: error: *** A compiler with support for C++11 language features is requir ...

  6. OpenGL 4.0 Shading Language Cookbook-中文版问世了

    OpenGL 4.0 Shading Language Cookbook-中文版问世了, http://item.taobao.com/item.htm?spm=a230r.1.14.13.K3kTO ...

  7. android studio项目报:Error:Jack is required to support java 8 language features. Either enable Jack

    1.问题描述: android studio项目报: Error:Jack is required to support java 8 language features. Either enable ...

  8. Vue Language Features (Volar) 会引起ts报错

    困扰了好一阵子的问题. {"name": "test","version": "0.1.0","private ...

  9. 为所有服务器端代码调用ConfigureAwait的最佳实践

    本文翻译自:Best practice to call ConfigureAwait for all server-side code When you have server-side code ( ...

最新文章

  1. 职称计算机 菏泽,山东菏泽2016年职称计算机首批考试时间
  2. ASA防火墙学习笔记1-基础篇
  3. Spring Cloud Alibaba 2021.0.1.0 发布:版本号再也不迷糊了
  4. jQuery表单对象属性过滤选择器
  5. Netflix是如何构建代码的
  6. 多线程threading初识,线程等待
  7. puppet变量、数据类型及类(03)
  8. Mtlab之图形标注
  9. Java 线程池学习
  10. Android Studio开发引入Speex
  11. 计算机cpu好坏之分,学查看CPU天梯图,正确判断CPU性能好坏
  12. 博客中常用的Emoji表情整理,欢迎自取
  13. 等离子显示器测试软件,等离子显示器驱动芯片内置ERC功能的测试方法
  14. android源代码在线查看
  15. 机器人工程→合适的规划←
  16. 抖音巨量千川是什么?和飞瓜智投有什么不同?后者功能更强大!
  17. 如何与其他用户共享SkyBell HD访问
  18. Python+selenium+360浏览器实现自动测试
  19. 很全的大数据分析平台
  20. poj 1129 四色原理DFS

热门文章

  1. React学习:入门实例-学习笔记
  2. python2.X在linux上的安装
  3. dockerfile构建nginx并结合php
  4. 小米开发出100W手机快充技术:实测逆天
  5. Java面试题—内部类和静态内部类的区别
  6. 《Linux From Scratch》第三部分:构建LFS系统 第六章:安装基本的系统软件- 6.69. Vim-7.4...
  7. (cljs/run-at (JSVM. :all) 一次说白DataType、Record和Protocol)
  8. SQL30081N 检测到通信错误。正在使用的通信协议:TCP/IP
  9. mssql查询所有上下级
  10. 9个高招,让企业WiFi速度飞起来!