C # 2.0 specification (ii)

Source: Internet
Author: User
Tags foreach anonymous count expression sin
19.1.5 generic method
In some cases, type parameters are not required for the entire class, and are required only for specific methods. Often, this is true when you create a method that accepts a generic type as a parameter. For example, when using the Stack<t> class described earlier, a generic pattern might be to push multiple values in a single line, and it would be convenient to write a method in one call. For a particular constructed type, such as Stack<int&gt, this method looks like this.

void Pushmultiple (stack<int> Stack, params int[] values)

{

foreach (int value in values)

Stack. Push (value);

}



This method can be used to press multiple int values into a stack<int>.

stack<int> stack = new stack<int> ();

Pushmultiple (Stack, 1, 2, 3, 4);

However, the previous method is only valid for a particular constructed type stack<int>. To make it work for stack<t>, the method must be written as a generic method. A generic method specifies one or more type parameters between the "<" and ">" delimiters after the name of the method. Type parameters can be used within the parameter list, the return type, and the method body. A generic Pushmultiple method would be like this.

void Pushmultiple<t> (Stack<>t Stack, params t[] values)

{

foreach (T value in values) stack. Push (value);

}

Using this generic method, you can press multiple entries into any stack<t>. When a generic method is invoked, the type parameter value is given in the angle brackets of the method call. For example

stack<int> stack = new stack<int> ();

Pushmultiple<int> (Stack, 1,2,3,4);

This generic Pushmultiple method is more reusable than the previous version because it works on any stack<t>, but it seems to be inconvenient at the time of invocation, since T must be passed as a type parameter to the method. In many cases, the compiler uses a method called type inferencing to infer the correct type parameters from other parameters passed to the methods. In the previous example, because the first formal argument was the stack<int> type, and subsequent arguments were of type int, the compiler could infer that the value of the type parameter must be int. Thus, you can call the generic Pushmultiple method without specifying the type parameter.

stack<int> stack = new stack<int> ();

Pushmultiple (Stack, 1, 2, 3, 4);

19.2 Anonymous Methods
Event handlers and other callback functions often need to be invoked through a dedicated delegate and are never called directly. Nonetheless, we can only place the event handle and the callback function's code in a specific method, and then explicitly create a delegate for that method. In contrast, anonymous methods (anonymous method) allow a delegate-associated code to be inline to write to the local method of the delegate, and conveniently this makes the code straightforward for the instance of the delegate. In addition to this convenience, anonymous methods also share access to function members that are contained in local statements. In order for a naming method to be shared (as distinct from an anonymous method), you need to create the auxiliary class manually and "promote (lifting)" The local member to the domain of the class.





The following example shows a simple input form that contains a list box, a text box, and a button. When the button is pressed, an item containing text in the text box is added to the list box.

Class Inputform:form

{

ListBox listbox;

TextBox textbox;

Button AddButton;

Pubic MyForm ()

{

ListBox = new ListBox (...);

TextBox = new TextBox (...);

Addbuton = new Button (...);

Addbutton.click + = new EventHandler (AddClick);

}

void AddClick (object sender, EventArgs e)

{

ListBox.Items.Add (textbox. Text);

}

}

Even if the response to the click event of a button has only one statement to execute. The statement must also be placed in a separate method with a complete argument list, and you must also manually create a EventHandler delegate that references that method. With anonymous methods, event-handling code becomes fairly concise.

Class Inputform:form

{

ListBox listbox;

TextBox textbox;

Button AddButton;

Pubic MyForm ()

{

ListBox = new ListBox (...);

TextBox = new TextBox (...);

Addbuton = new Button (...);

Addbutton.click +=delegate{

LISTBOX.ITEMS.ADD (TextBox.Text.);

}

}

The anonymous method consists of a keyword delegate and an optional list of arguments, and a statement enclosed in the "{" and "}" delimiters. In the previous example, the anonymous method did not use the arguments provided by the delegate, so the argument list was omitted. If you want to access a parameter, the anonymous method can contain a list of parameters.



Addbutton.click + = Delegate (object sender, EventArgs e) {

MessageBox.Show ((Button) sender). Text);

};

In the previous example, an implicit conversion of the anonymous method to the EventHandler delegate type (the type of the Click event) occurs. This implicit conversion is possible because the return value of the argument list and delegate type is compatible with the anonymous method. The exact rules on compatibility are as follows:

If one of the following is true, the parameter list of the delegate is compatible with the anonymous method.
-The anonymous method has no argument list, and the delegate has no out parameters.

-An anonymous method contains a parameter list that exactly matches the parameters of the delegate on the number, type, and modifier.

If one of the following is true, the return type of the delegate is compatible with the anonymous method.
-The return type of the delegate is void, the anonymous method does not return a statement, or it has only a returned statement without an expression.

-The return type of the delegate is not void, and in an anonymous method, the expression associated with all returns statements can be implicitly converted to the type of the delegate.



Before an implicit conversion of a delegate type occurs, both the argument list and the return type of the delegate must be compatible with the anonymous method.

The following example uses an anonymous method to write an "inline" function. Anonymous methods are passed as function delegate types.

Using System;

Delegate double Function (double x);

Class Test

{

Static double[] Apply (double[] A, Function f)

{

Double[] result = new Double[a.length];

for (int i=0;i<a.length;i++) result[i] = f (a[i]);

return result;

}

Static double[] MultiplyAllBy (double[] A, double factor)

{

Return to Apply (A, delegate (double x) {return x*factor;})

}

static void Main ()

{

Double[] A = {0.0,0.5,1.0};

double[] Squares = Apply (A, delegate (double x) {return x*x});

double[] Doubles = MultiplyAllBy (A, 2.0);

}

}



The Apply method applies the given function of a double[] element and returns a double[] as the result. In the main method, the second parameter passed to apply is an anonymous method that is compatible with the Fucntion delegate type. The anonymous method simply returns the square of the argument, and the result of the apply call is a double[], which contains the square of the value in a.

The MultiplyAllBy method returns a double[that is created by multiplying each value in the parameter array A by a given factor (factor). To get the result, MultiplyAllBy invokes the Apply method and passes it an anonymous method (in which the parameter is superior to the factor factor).

If the scope of a local variable or parameter includes an anonymous method, the variable and parameter are referred to as external variables (outer variable) of the anonymous method. In the MultiplyAllBy method, a and factor are external variables that are passed to an anonymous method of apply because the anonymous method refers to the factor,factor being captured by an anonymous method (capture). Typically, the lifetime of a local variable is limited to the execution area of the block or statement it is associated with. However, the captured external variable will persist until the anonymous method referenced by the delegate can be garbage collected.

19.2.1 Method Group Conversion
As described earlier, an anonymous method can be implicitly converted to a compatible delegate type. For a method group, c#2.0 allows this same type of conversion, that is, in almost any case, there is no need for an explicit instantiation of the delegate. For example, the following statement

Addbutton.click + = new EventHandler (AddClick);

Apply (A, new Function (Math.sin));

Can be replaced by the following statement.

Addbutton.click + = AddClick;

Apply (A, math.sin);

When this short form is used, the compiler automatically infers which delegate type needs to be instantiated, but its final effect is the same as the longer expression.



19.3 iterators
C # 's foreach statement is used to iterate over all elements of an enumerable (enumerable) collection. In order to be enumerated, the collection must have a parameterless GetEnumerator method that returns a Enumertor (enumerator). In general, enumerators are difficult to implement, but the problem is greatly simplified using iterators.

An iterator is a statement block that produces an ordered sequence of values. An iterator differs from a regular block of statements that has one or more yield statements.

The yield return statement produces the next value of the iteration.
The yield break statement indicates that the iteration is complete.
The iterator can be used as a function body as long as the return type of the function member is one of the enumerator interface (enumerator interface) or an enumerable interface (enumerable interface).

The enumerator interface is the System.Collections.IEnumerator and the type constructed by sysetm.collections.generic.ienumerator<t>.
An enumerable interface is a System.Collections.IEnumerable and a type constructed by system.collections.generic.ienumerable<t>.


An iterator is not a member, it is just a way of implementing a function member, it is important to understand this. A member that is implemented through an iterator and can be overwritten and overloaded by other members that might or may not be implemented through iterators.

The following Stack<t> class uses an iterator to implement its GetEnumerator method. This iterator enumerates all the elements of the stack from top to bottom in sequence.

Using System.Collections.Generic;

public class Stack<t>:ienumerable<t>

{

t[] items;

int count;

public void Push (T data) {...}

Public T Pop () {...}

Public ienumerator<t> GetEnumerator ()

{

for (int i =count-1;i>=0;--i) {

Yield return items[i];

}

}

}



The existence of the GetEnumerator method makes stack<t> an enumerable type that allows instances of stack<t> to be used in a foreach statement. The following example presses the value from 0 to 9 into an integer stack and displays all values from the top of the stack using a foreach loop.

Using System;

Class Test

{

static void Main ()

{

stack<int> stack = new stack<int> ();

for (int i=0;i<10;i++) stack. Push (i);

foreach (int i in stack) Console.Write ("{0}", i);

Console.WriteLine ();

}

}

Example of the output into the following:

9 8 7 6 5 4 3 2 1 0

The foreach statement implicitly invokes the parameterless GetEnumerator method of the collection to obtain an enumerator. Only one such parameterless GetEnumerator method is defined by the collection, but there are often multiple enumerations and methods of controlling enumerations through parameters. In this case, the collection can use the iterator implementation to return the properties and methods of one of the enumerable interfaces. For example,,stack<t> may introduce two new properties of the ienumerable<t> type, TopToBottom and BottomToTop.

Using System.Collections.Generic;

public class Stack<t>: ienumerable<t>

{

t[] items;

int count;

public void Push (T data) {...}

Public T Pop () p{...}

Public ienumerator<t> GetEnumerator ()

{

for (int i= count-1;i>=0;--i)

{

Yield return items[i];

}

}

Public ienumerable<t> topbottom{

get{

return this;

}

}

Public ienumerable<t> bottomtotop{

get{

for (int I = 0;i<count;i++)

{

Yield return items[i];

}

}

}

}

The get accessor of the TopToBottom property simply returns this, because the stack itself is enumerable. The BottomToTop property returns an enumeration implemented using the C # iterator. The following example shows how a property is used to enumerate stack elements.

Using System;

Class Test

{

static void Main ()

{

stack<int> stack = new stack<int> ();

for (int i = 0; i<10 i++) stack. Push (i);

for (int i in stack.. TopToBottom) Console.Write ("{0}", i);

Console.WriteLine ();

for (int i in stack.. BottomToTop) Console.Write ("{0}", i);

Console.WriteLine ();

}

}

Of course, these properties can also be used outside of a foreach statement. The following example passes the result of the calling property to a separate print method. This example also shows an iterator for a method body that is used as a fromtoby to accept parameters.

Using System;

Using System.Collections.Generic;

Class Test

{

static void Print (Ienumerable<int> collection)

{

foreach (int i in collection) Console.Write ("{0}", i);

Console.WriteLine ();

}

static ienumerable<int> Fromtoby (int from, int to, int by)

{

for (int i =from; i<=to i +=by)

{

Yield return I;

}

}



static void Main ()

{

stack<int> stack = new stack<int> ();

for (int i= 0; i<10;i + +) stack. Push (i);

Print (Stack. TopToBottom);

Print (Stack. BottomToTop);

Print (Fromtoby (10,20,2));

}

}



The output of this example is as follows.

9 8 7 6 5 4 3 2 1 0

0 1 2 3 4 5 6 7 8 9

10 12 14 16 18 20

The generic and Non-generic enumerable interfaces contain a single member, a GetEnumerator method that does not accept parameters, and an enumerator interface. An enumeration acts as an enumerator factory. A separate enumerator is generated whenever a GetEnumerator method of a class that implements the enumerable interface is invoked correctly. Assuming that the internal state of the enumeration has not changed between the two call GetEnumerator, the returned enumerator should produce an enumerated value in the same order as the collection. In the following example, this should be maintained even if the lifetime of the enumeration occurs overlapping.

Using System;

Using System.Collections.Generic;

Class Test

{

static ienumerable<int> FromTo (int from, int to)

{

while (from<=to) yield return from++;

}



static void Main ()

{

Ienumerable<int> e = FromTo (1,10);

foreach (int x in E)

{

foreach (int y in e)

{

Console.WriteLine ("{0,3}", x*y);

}

Console.WriteLine ();

}

}

}

The previous code printed a multiplication table of integers 1 through 10. Note that the FromTo method is invoked only once to produce an enumeration E. However, E.getenumerator () was invoked multiple times (via a foreach statement) to produce multiple equivalent enumerators. These enumerators encapsulate the iterator code specified in the FromTo declaration. Note that the iterator code modifies the from parameter.

However, the enumerator operates independently because each enumerator gives its own copy of From and to. The sharing of transition state between enumerators is one of the many subtle flaws that should be avoided when implementing enumerations and enumerators. The design of the C # iterator can be used to avoid these problems, thereby implementing robust enumerations and enumerators in a simple and intuitive manner.



Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.