Apress Introducing Dot Net 4 With Visual Studio_8

Apress Introducing Dot Net 4 With Visual Studio_8

Thể loại: Hệ điều hành
Lượt xem: 59,468Lượt tải: 4Số trang: 59

Mô tả tài liệu

Tham khảo tài liệu 'apress introducing dot net 4 with visual studio_8', công nghệ thông tin, hệ điều hành phục vụ nhu cầu học tập, nghiên cứu và làm việc hiệu quả

Tóm tắt nội dung

Using extension methods, operation chaining becomes a more natural could not have done in the C# 2.0 days using plain static methods and anonymous by a squaring and the end result is a type that method, similar to that takes a predicate delegate as a parameter and uses it to This class provides a whole host of extension methods that All these extension methods operate on types Also, the class provides the same extension methods for types methods offer even more to create custom iterators for in a very that don’t support as I’ll show in the next section, from Let’s look at how you can use extension methods to implement custom iterators on types example, imagine a matrix as a type. var matrix = new { new List<int> { 1, 2, 3 }, new List<int> { 4, 5, 6 }, new List<int> { 7, 8, 9 } using an extension method: var matrix = new { new List<int> { 1, 2, 3 }, new List<int> { 4, 5, 6 }, new List<int> { 7, 8, 9 } In this version, I have the iteration into the extension the same time, I made the extension method generic so it will accept nested lists You might have already noticed that many of the new features added in C# 3.0 a You’ve always been able to implement models in C#, but the new language features make it easier by making the language more Caution Although I have named this type IList<T> for this example, be sure not to confuse it with IList<T> in In the following example code, I create a custom list called MyList<T> that static IList<T> items ) { public static IList<T> iter ) { var listInts = new List<int> { 1, 2, 3, 4 }; static method populates using these in Main uses this iterator to send all the list items to the the example, notice that the method creates a forward iterator by making Check out the following revised version of the iterator extension method and the Main method: var listInts = new List<int> { 1, 2, 3, 4 }; var iterator = delegate( list ) { list ) { Notice that the method accepts two more one of which is then called Main method, I am passing two delegates in the form of anonymous method can be used to iterate over every other item in the list simply by modifying ■ Note Some of you might already be familiar with lambda which were in C# 3.0. when using lambda you can clean up this code by using the lambda syntax I cover lambda in Chapter 15. As a final extension method example for on the IList<T> type, consider how we could create an extension method to reverse the list and return a new along the way.3 In the preceding code, the anonymous method is assigned to the In a way, the anonymous method captures initiates the chain of recursive calls to the anonymous method and then passes the resulting List<T> to the method, thus creating the reversed the temporary List<T> entirely and build the new MyList<T> using a captured variable as The previous method first creates an anonymous function and stores it in the local It then returns the results of calling the anonymous method to the caller of method and the captured local variables and itself until it is finished building the reversed list into the captured extension method can be cleaned up by the captured variable and the method uses only the stack as a temporary storage location while building the new = list, IList<T> result) { return new result) ); ■ Note This code uses the Func<> which is a generic delegate that is defined in the System Using Func<> is a shortcut you can employ to avoid having to declare delegate types all over the You use the Func<> type parameter list to declare what the parameter types (if any) and return type of the If the delegate you need has no return value, you can use the Action<> generic delegate type. The MyList<T> class used in the previous examples builds the linked list from the type entirely before the MyList<T> object can be used. If you are creating a library for general use that contains a type such as For example, consider a of types that might or might not be related by and way to do it is to introduce a new base type that derives from Validate as an abstract method, and then makes all the other types derive from the new type instead of a of unrelated types, you will probably implement a host of extension static class public static void Validate( this Employee emp ) { public class Employee Notice that for each type of object we want to validate (in this example there are three), I have defined a separate Validate extension method is being called for each instance and is as follows: In this example, it’s important to note that the visitors, in this case the extension methods named ■ Note Keep in mind that if the extension methods are defined in the same assembly as the types they are form of the Validate extension method that can be used if the instance supports a Validate method that will be called if the type the static class public static void Validate( this Employee emp ) { "Instance of following type" + public class Employee not a version of Validate that takes the type as its first the generic form of Validate will be called, which then passes through to the method on the that I removed the extension method whose first parameter was of type so method to generic forms of the extension method that accept one generic type you how they can be used to create useful things such as iterators types) on Even for types that do have you can define lambda extension methods provide a certain degree of that is extremely While showing how to create custom I took a slight detour (using anonymous functions rather than lambda to show you the world of that the features The code for those examples will become much cleaner when you use lambda instead of anonymous the next chapter, I’ll introduce you to lambda which really make into either code or data in the form of IL code or an tree, Most of the new features of C# 3.0 opened up a world of to the C# language, and one can use and implement in C# 3.0 the language into a more hybrid language in which both and Lambda are arguably the to Lambda Using lambda you can define function objects for use at any this via whereby you create a function object (in the form of a delegate) Lambda join these two and one statement in the that takes functions in its parameter list and operates on those possibly even Lambda provide In simple syntactic terms, lambda are a syntax whereby you can declare anonymous in a more fluid and way. Just about every use of an anonymous method can be replaced with a lambda CHAPTER 15 ■ LAMBDA first, the syntax of lambda might take some time to get used when you are looking at a lambda all by really take two lambda are a direct for anonymous on Both types of lambda can be converted However, lambda without statement blocks offer something truly can convert them into trees based on the types in the creating trees from lambda in the section titled Trees” later in this Lambda and Closures First, let’s look at the simpler form of lambda that is, the ones without a statement in the previous section, a lambda is a shorthand way of declaring a simple The following lambda can be used as a delegate that accepts one What this says is “take x as a parameter and return the result of following operation on x.” Notice that the lambda is devoid of any type the compiler will deduce the type of the argument x and the type of the result depending on the It means that if you are assigning a lambda to a delegate, the types of the delegate are used to determine the types within the lambda shows what happens when a lambda is assigned to a delegate type: I have marked the lambda in bold so that it stands out. 3 I covered some examples of with anonymous methods in Chapter 15 ■ LAMBDA When the compiler assigns the lambda to the expr variable, it uses the type of the delegate to determine that the type of x must be int, and the type of the You can fix this by different types in the delegate as shown here: For the sake of this lambda has what’s called an typed list, and in this case, x is declared as type parameter list in a lambda and assign it to a delegate, the argument types ■ Note When using typed parameter lists, notice that the parameter list must be enclosed in of only one typed the lambda is assigned to a delegate, the return type of the is generally So, in the following code the return type of the is double because the inferred type of the parameter x is double: error CS1662: Cannot convert 'lambda to delegate type because some of the return CHAPTER 15 ■ LAMBDA types in the block are not to the delegate return type You can “fix” this by casting the result of the lambda body to int: ■ Note Explicit types in lambda parameter lists are required if the delegate you are assigning them to One could argue that fixing the parameter types within a lambda Now I want to show you a simple lambda that accepts no Notice how simple it was to pass a function as a parameter into the method using this lambda I want to show you an example of a lambda that accepts more than one CHAPTER 15 ■ LAMBDA var = new { In this case, the lambda is used to create a delegate that accepts two of type As you can see, lambda provide a nice, succinct way of creating how to use lambda as to create flexible delegate int CHAPTER 15 ■ LAMBDA Look at all the work involved without lambda this case, the is a pointer to the counter variable in the Main of the code cannot be verified by the CLR.4 Then, in the Main method, I created an instance of CHAPTER 15 ■ LAMBDA public field of the generated class that the closure with a reference to the captured variable or a copy if the captured variable is a value an instance of it in C# code because the name itself, if typed in code, will generate a syntax error. In C# 2.0, anonymous methods were to reduce the burden I just not as as lambda because they still carry the old style with them and require parameter types in the parameter would be using anonymous methods, so you can see the in syntax from lambda I have bolded the between this example and the original lambda still not as and succinct as the lambda lambda you CHAPTER 15 ■ LAMBDA ■ Note In the previous code example, you likely noticed the of the counter variable within the lambda Variable I described how you can do the same thing with anonymous essence, any time a lambda the All the lambda I have shown so far have been purely of the type of lambda is one I like to call a lambda is similar in form to the lambda shown in the previous section can be converted to a lambda with a statement block simply by the with curly braces after prefixing the right side with a return example, the following lambda In form, lambdas with statement blocks are almost identical to anonymous major between lambdas with statement blocks and lambda blocks can be converted only to delegate types, whereas lambda can be converted both to delegates and to trees typed by the family of types centered around Note The big between lambdas with statement blocks and anonymous methods is that anonymous methods must type their whereas the compiler can infer the types of the lambda based on The syntax offered by lambda fosters a more Trees So far, I have shown you lambda that replace the of lambda into trees based on the types in the CHAPTER 15 ■ LAMBDA you’ve already seen how you can convert a lambda into a delegate as shown here: In this line of code, the is converted into a delegate that accepts a single int parameter int>> expr = n => n+1; The lambda instead of being converted into a callable delegate, is The type of the expr variable is where T is replaced with the type of delegate the lambda can be converted notices that you are trying to convert the lambda into an instance and generates all the code to make it later in time, you can then compile the into a usable delegate as shown in the next using int>> expr = n => n+1; The line in bold shows the step at which the is compiled into a multiple trees to create more complex trees prior to compiling them. One could even define a new language or implement a parser for an already existing fact, the compiler acts as an parser when you assign a lambda into an type tree and if you use ILDASM or Reflector to look at the generated code, you can see it in The previous example could be rewritten without using the lambda as follows: using var n = "n" ); CHAPTER 15 ■ LAMBDA var expr = assigned the lambda n => this longhand example helps express the true of of the lambda n = "n" ); ■ Note In these examples, I am using typed variables to save myself a lot of typing and to reduce clutter the variables are still strongly line of code says that we need an to represent a variable named n that is of type that in a plain lambda this type can be inferred based upon the delegate type the number 1, to an the parameter of building block of trees, using the new operator along with the of the type. The is not so you must use the static methods on the class to create to decide which type we really 15 ■ LAMBDA you will notice that there are no public on these types. of derived types using the type, which the factory pattern and exposes static methods for creating instances of derived that you have the you need to use the method to bind the (in this case, n+1) with the in the parameter list (in this case, n). the example I use the generic Lambda<> method so that I can create the type more point I want to make that how represent as data is expr variable, you will notice that in either the “Autos” or “Locals” windows, the is parsed and trees. ■ Note If I had used the version of the method, the result would have been an instance of rather than however, instead of a strongly typed delegate, it returns an instance of type the Delegate instance, you must cast it to the specific delegate type; in this case, Func<int, int> or could throw an exception at run time if you have a mismatch between your and the type of delegate on Now I want to show you an example of how you can take an tree generated from a lambda and modify it to create a new tree. In this case, I will take the (n+1) and using expr = n => n+1; CHAPTER 15 ■ LAMBDA // by 2. expr = ), The bolded lines show the stage at which I multiply the original lambda by to notice that the passed into the Lambda<> method (the second need to be exactly the same instances of the that come from the original that is, Lambda<> method; at run time you will receive an exception similar to the following because There are many classes derived from the class and many static methods for creating of them and combining other namespace for all the fantastic trees and how Lisp and similar languages represent functions as data you might already guess, within the scope of C#, trees are extremely useful when most important fact is that LINQ provides a syntax for to search a large in-memory array (or any other type) for items that match a LINQ is and can provide a means of operating on other types of stores, such on any type that supports 15 ■ LAMBDA LINQ might be. If the LINQ is in data (as an tree) rather than in IL (as a Or maybe when your analyzes the data, you can translate the tree into the final operation via a mechanism such as Had the only been available as IL code from power of trees in of Lambda Now that I have shown you what lambda look like, let’s consider some of the things you can You can actually implement most of the following examples in C# using anonymous methods or I want to how you can use lambda to create custom want to show how you can iterate over a generic type that might or might not be a in the from the custom iterator creation method, including the type of the item stored, the type of CHAPTER 15 ■ LAMBDA is the type of the which in this example is specified as at the point of is the type that the code returns via the yield are delegate types that it uses to determine how to iterate over the 15 ■ LAMBDA First, it needs a way to access the current item in the which, for this example, is expressed in the following lambda which uses the values within the cursor array to index the item supply the following lambda that just checks to see whether the cursor has stepped off of the lambda which simply advances both of the cursor: Other of could accept a first parameter of type given to access the current each value by 2 in the lambda that accesses the current item in the lambda syntax to C# opens one’s eyes to the 15 ■ LAMBDA CHAPTER 15 ■ LAMBDA concept in many ways, even creating a random number generator using C# variable delta and the delegate func embody the the captured variable is to both the delegate and the context the lambda it means that the captured variable can be changed outside the scope and out of band of the In essence, two methods (Main and the delegate) both have access to 15 ■ LAMBDA ■ Note In reality, when a closure is formed, the C# compiler takes all those variables and wraps them up in a It also the delegate as a method of the is that the function itself is treated as a object that can be and You’ve already seen how lambda can be converted into trees so you can operate on them, producing more or less complex a quick example of what I mean, consider two lambda You could create a method to combine such lambda to create a compound lambda the Main method, you can see how I used it to produce the compound after calling Chain<> is to the delegate you get when you convert the following lambda into a delegate: Having a method to chain arbitrary like this is useful indeed, but let’s look at other ways CHAPTER 15 ■ LAMBDA But instead of modifying the original let’s look at how to create a method that accepts the original delegate as a parameter and returns a new delegate to replace the has no entropy, meaning that for the same input it always returns the same set has already been computed and return it rather than calling the 15 ■ LAMBDA public static class Memoizers method to the delegate to produce a new Memoize<> method wraps the original delegate that’s CHAPTER 15 ■ LAMBDA CHAPTER 15 ■ LAMBDA For that matter, many more useful things can be done with methods that accept functions and In the previous section on closures I how to create a method that accepts a function, given as a delegate, and produces a new of In short, what it means is creating an operation (usually a method) that accepts Suppose that you have a lambda that looks like the Now, suppose that you have a list of doubles and you want to use this lambda to add a constant value to each item on the list, producing a new based on the original lambda in which one of the variables is forced to a static 15 ■ LAMBDA var mylist = new { 1.0, 3.4, 5.4, 6.54 }; // Here is the original meat of this example is in the Bind2nd<> extension method, which I have it creates a closure and returns a new delegate that accepts only one delegate is called, it passes its only parameter as the first parameter to the original delegate and var mylist = new { 1.0, 3.4, 5.4, 6.54 }; CHAPTER 15 ■ LAMBDA // Here is the original original function to) and returns another delegate that is the curried which fact is assigned the lambda for the factorial captures the fact delegate Remember that even though a closure captures a variable for use inside the anonymous method, which is here as a lambda the captured variable is still and mutable from outside the context of the capturing anonymous method or lambda 15 ■ LAMBDA We fact to reference a new delegate based on the lambda But still the lambda (x) => x > 1 the new (x) => x+1, which is different behavior from the recursion you had the captured variable (the func delegate) are several ways to fix this problem, but the typical method is to use anonymous What ends up happening is that you modify the preceding factorial lambda to accept another and converts the captured variable into a parameter to the that is passed on the stack (in this case, the parameter f in the fact this chapter, I you to the syntax of lambda which are, for the most part, In fact, it’s a shame that lambda did not come along with C# 2.0 because then there would have been no need for anonymous convert lambda with and without statement bodies, into how lambda without statement bodies are to trees based on the type as defined in the trees, you can apply to the tree before actually compiling it into a delegate and calling CHAPTER 15 ■ LAMBDA I finished the chapter by showing you useful of lambda by using closures, delegate parameter binding using 2.0 using anonymous methods, the of lambda syntax to the language makes using such and of we have features like lambda anonymous types, extension methods, and typed At first glance, LINQ query look a lot like SQL all, C# is a strongly typed language, and so is The language adds several new keywords for building query query typically get into a chain of extension method calls on a sequence or is clearly defined, and they are called standard query the compiler merely query into a series of method calls, it follows that you can provide your own of those extension example, the class provides of those methods for LINQ to Objects, whereas provides of those methods for querying types that implement and are commonly used with LINQ to I create a of Employee objects and then perform a simple query: public class Employee var employees = new { titled “Standard Query In this example, I marked the query in bold to make it It’s quite shocking if it’s the first time you have seen a LINQ SQL, the select clause is normally the beginning of the to the query I created a simple list of Employee instances just to have some data to Each query starts off with a from clause, which declares what’s called a range from clause in our example is very similar to a foreach statement in that it iterates over the employees and stores each item in the in the variable employee during each the closes with select, which is a perform a in the query you are typically creating another of Another thing to note is my use of anonymous types in the select prior to my query and made my select clause instances of that type, but doing so defeats some of the and of the LINQ does not execute at the point the query variable is and the use of foreach on the query variable produces The end result of building the query in what’s called a query variable, which Notice that I reference it using an typed what the type of query Methods and Lambda Revisited Before I break down the elements of a LINQ in more detail, I want to show you an alternate the compiler simply the LINQ into a series of extension method calls that accept lambda usable on types, whereas Queryable defines the same of generic methods usable on see they have names just like the clauses in query methods implement the standard query operators I mentioned in the previous query in the previous example can be replaced with the following code: Notice that it is simply a chain of extension method calls on which is by method syntax and simply call them as static methods, as shown here: methods could even go one step further and replace the lambda with anonymous to say, the and Queryable extension methods are very useful even outside the And as a matter of fact, some of the provided by the extension methods LINQ is built upon the use of standard query which are methods that operate on sequences compiler a query it typically converts the into a series or chain of calls to those extension methods that implement the query by calling the extension methods as code with query extension methods, and a complete query might be extension methods, and the compiler will generate calls to them while compiling a LINQ query finding the extension methods in I provide my own of the standard query operators Where and Select that simply you cannot use a LINQ query because the from clause requires a data source C# 2008 a small set of new keywords for creating LINQ query some of which we which is a local variable of sorts used to represent each item of the input as the query is applied to it. A query might contain more than one from that LINQ are compiled into strongly typed code. The compiler infers the types of those two range variables based upon the type argument of the interface returned by Range returns a type of the type of x and y is int. to apply a query to a that only supports the cases, you must specify the type of the range variable, as shown here: var query = from int n in numbers You can see where I am typing the range variable n to type typed languages such as C# rely upon the compiler to verify the integrity of the you perform on the types defined within the if there is a type- var employees = new { In the query I have the join building the result and projects that data into an anonymous your query contains a join the compiler converts it to a Join extension method call the GroupJoin extension method which also groups the consist of the where keyword followed by a predicate is into a call to the Where extension method, and the predicate is passed to the Where method as a lambda an type, convert the lambda into a the lambda into an tree.2 I’ll have more to say about trees in public class Employee var employees = new { 2 In Chapter 15, I show how lambda that are assigned to delegate instance variables are converted into IL code, whereas lambda that are assigned to are converted into trees, thus the with data rather than that because the select clause simply returns the range variable, this whole query is nothing more than a sort example, I sort first by in ascending order, then the second in the orderby clause sorts the results of each group by LastName in order, and then each of At compile time, the compiler the first in the orderby clause into a call to the OrderBy standard query operator extension a LINQ query, the select clause is used to produce the end result of the any filtering where clauses in the query they must precede the select converts the select clause into a call to the Select extension is converted into a lambda that is passed into the Select method, which uses it to types feature was born from the select operation during the of LINQ. why anonymous types are so handy in this case, consider the following example: public class Result However, notice that I had to declare a new type Result just to hold the results of the use anonymous types as follows: I can go and add a new property to the result type and call it Output2, for example, and it would not force any changes on anything other than the anonymous type inside the query code will continue to work, and anyone who wants to use the new Of course, there are some where you do want to use types in the select clause such as when one of those type instances has to be returned from a of it as a local variable that is visible only within the query just as a local public class Employee var employees = new { you can use the variable as input to another from clause to create a new derived range In the previous section titled “The from Clause and Range I gave an example using The query can have an optional group clause, which is very powerful at the input As you can see, this simple query iterated over all the items from the source data In order to perform such a grouping, you can use an anonymous type to introduce the multiple keys into public class Employee Notice the anonymous type within the group how it works is that for each item, it builds an instance of the anonymous type and If not, a new group is created with that instance of the anonymous type as the an into clause, you tell the query that you want to assign the results of a group or a join C# Is a Strongly Typed and and Typed Local new with Value new with Class Parameter Define of Side Effects of Value Types Interface with Value and Formats of of String in Custom Types, and That Produce Anonymous and Methods as Delegate Parameter Value and Operators within Generic Types for Reference Type-Safe Forms of Interface Members and Derived Does the Compiler Find Extension a Type’s Contract Can Break Extension to Lambda and on of Lambda Methods and Lambda Typing in C#