I want to execute a javascript function on response postback.
I know window.onload=function(){...}, it's init the page,
but I want to reset the page control properties by javascript after the postback, not directly from server.
I have a btnOK, I add the following snippet under btnOK_Click(sender, e);
ScriptManager.RegisterStartupScript(updPanel, GetType(string), "funName", "Alert('hello word!');", True)
It will create a javascript snippet in html on response back. and execute it. on page refresh, it will alert hello word.
2010年12月29日星期三
2010年12月14日星期二
Extension Methods (C# Programming Guide)
Extension Methods (C# Programming Guide)
The following example shows how to call the standard query operator OrderBy method on an array of integers. The expression in parentheses is a lambda expression. Many standard query operators take lambda expressions as parameters, but this is not a requirement for extension methods.
=============================================================
class ExtensionMethods2
{
static void Main()
{
int[] ints = { 10, 45, 15, 39, 21, 26 };
var result = ints.OrderBy(g => g);
foreach (var i in result)
{
System.Console.Write(i + " ");
}
}
}
//Output: 10 15 21 26 39 45
=============================================================
Extension methods are defined as static methods but are called by using instance method syntax.
Their first parameter specifies which type the method operates on, and the parameter is preceded by the this modifier.
Extension methods are only in scope when you explicitly import the namespace into your source code with a using directive.
The following example shows an extension method defined for the System.String class. Note that it is defined inside a non-nested, non-generic static class:
=============================================================
namespace ExtensionMethods
{
public static class MyExtensions
{
public static int WordCount(this String str)
{
return str.Split(new char[] { ' ', '.', '?' },
StringSplitOptions.RemoveEmptyEntries).Length;
}
}
}
The WordCount extension method can be brought into scope with this using directive:
And it can be called from an application by using this syntax:
=============================================================
string s = "Hello Extension Methods";
int i = s.WordCount();
The following example implements an extension method named WordCount in the MyExtensions.StringExtension class
=============================================================
using System.Linq;
using System.Text;
using System;
namespace CustomExtensions
{
//Extension methods must be defined in a static class
public static class StringExtension
{
// This is the extension method.
// The first parameter takes the "this" modifier
// and specifies the type for which the method is defined.
public static int WordCount(this String str)
{
return str.Split(new char[] {' ', '.','?'}, StringSplitOptions.RemoveEmptyEntries).Length;
}
}
}
namespace Extension_Methods_Simple
{
//Import the extension method namespace.
using CustomExtensions;
class Program
{
static void Main(string[] args)
{
string s = "The quick brown fox jumped over the lazy dog.";
// Call the method as if it were an
// instance method on the type. Note that the first
// parameter is not specified by the calling code.
int i = s.WordCount();
System.Console.WriteLine("Word count of s is {0}", i);
}
}
}
ref: http://msdn.microsoft.com/en-us/library/bb311042.aspx
The following example shows how to call the standard query operator OrderBy method on an array of integers. The expression in parentheses is a lambda expression. Many standard query operators take lambda expressions as parameters, but this is not a requirement for extension methods.
=============================================================
class ExtensionMethods2
{
static void Main()
{
int[] ints = { 10, 45, 15, 39, 21, 26 };
var result = ints.OrderBy(g => g);
foreach (var i in result)
{
System.Console.Write(i + " ");
}
}
}
//Output: 10 15 21 26 39 45
=============================================================
Extension methods are defined as static methods but are called by using instance method syntax.
Their first parameter specifies which type the method operates on, and the parameter is preceded by the this modifier.
Extension methods are only in scope when you explicitly import the namespace into your source code with a using directive.
The following example shows an extension method defined for the System.String class. Note that it is defined inside a non-nested, non-generic static class:
=============================================================
namespace ExtensionMethods
{
public static class MyExtensions
{
public static int WordCount(this String str)
{
return str.Split(new char[] { ' ', '.', '?' },
StringSplitOptions.RemoveEmptyEntries).Length;
}
}
}
The WordCount extension method can be brought into scope with this using directive:
And it can be called from an application by using this syntax:
=============================================================
string s = "Hello Extension Methods";
int i = s.WordCount();
The following example implements an extension method named WordCount in the MyExtensions.StringExtension class
=============================================================
using System.Linq;
using System.Text;
using System;
namespace CustomExtensions
{
//Extension methods must be defined in a static class
public static class StringExtension
{
// This is the extension method.
// The first parameter takes the "this" modifier
// and specifies the type for which the method is defined.
public static int WordCount(this String str)
{
return str.Split(new char[] {' ', '.','?'}, StringSplitOptions.RemoveEmptyEntries).Length;
}
}
}
namespace Extension_Methods_Simple
{
//Import the extension method namespace.
using CustomExtensions;
class Program
{
static void Main(string[] args)
{
string s = "The quick brown fox jumped over the lazy dog.";
// Call the method as if it were an
// instance method on the type. Note that the first
// parameter is not specified by the calling code.
int i = s.WordCount();
System.Console.WriteLine("Word count of s is {0}", i);
}
}
}
ref: http://msdn.microsoft.com/en-us/library/bb311042.aspx
Filtering with DataView (LINQ to DataSet)
Creating DataView from a Query with Filtering Information
=====================================================
Dim orders As DataTable = dataSet.Tables("SalesOrderDetail")
Dim query = _
From order In orders.AsEnumerable() _
Where order.Field(Of Int16)("OrderQty") > 2 And _
order.Field(Of Int16)("OrderQty") < 6 _
Select order
Dim view As DataView = query.AsDataView()
bindingSource1.DataSource = view
The following example creates a DataView from a query for orders placed after June 6, 2001:
=====================================================
Dim orders As DataTable = dataSet.Tables("SalesOrderHeader")
Dim query = _
From order In orders.AsEnumerable() _
Where order.Field(Of DateTime)("OrderDate") > New DateTime(2002, 6, 1) _
Select order
Dim view As DataView = query.AsDataView()
bindingSource1.DataSource = view
The following example uses the SoundEx algorithm to find contacts whose last name is similar to "Zhu". The SoundEx algorithm is implemented in the SoundEx method.
=====================================================
Dim contacts As DataTable = dataSet.Tables("Contact")
Dim soundExCode As String = SoundEx("Zhu")
Dim query = _
From contact In contacts.AsEnumerable() _
Where SoundEx(contact.Field(Of String)("LastName")) = soundExCode _
Select contact
=====================================================
Dim view As DataView = query.AsDataView()
bindingSource1.DataSource = view
dataGridView1.AutoResizeColumns()
Using the RowFilter Property
=====================================================
Dim contacts As DataTable = dataSet.Tables("Contact")
Dim view As DataView = contacts.AsDataView()
view.RowFilter = "LastName='Zhu'"
bindingSource1.DataSource = view
dataGridView1.AutoResizeColumns()
Dim contacts As DataTable = dataSet.Tables("Contact")
Dim query = _
From contact In contacts.AsEnumerable() _
Where contact.Field(Of String)("LastName") = "Hernandez" _
Select contact
Dim view As DataView = query.AsDataView()
bindingSource1.DataSource = view
dataGridView1.AutoResizeColumns()
view.RowFilter = "LastName='Zhu'"
After a DataView has been created from a DataTable or LINQ to DataSet query, you can use the RowFilter property to specify subsets of rows based on their column values. The string-based and expression-based filters are mutually exclusive. Setting the RowFilter property will clear the filter expression inferred from the LINQ to DataSet query, and the filter expression cannot be reset.
The filter on a DataView can be cleared after filtering has been set using the RowFilter property. The filter on a DataView can be cleared in two different ways:
■Set the RowFilter property to null.
■Set the RowFilter property to an empty string.
=====================================================
Dim orders As DataTable = dataSet.Tables("SalesOrderHeader")
Dim query = _
From order In orders.AsEnumerable() _
Where order.Field(Of DateTime)("OrderDate") > New DateTime(2002, 11, 20) _
And order.Field(Of Decimal)("TotalDue") < New Decimal(60.0) _
Select order
Dim view As DataView = query.AsDataView()
bindingSource1.DataSource = view
view.RowFilter = Nothing
=====================================================
Dim contacts As DataTable = dataSet.Tables("Contact")
Dim view As DataView = contacts.AsDataView()
view.RowFilter = "LastName='Zhu'"
bindingSource1.DataSource = view
dataGridView1.AutoResizeColumns()
' Clear the row filter.
view.RowFilter = ""
=====================================================
Dim orders As DataTable = dataSet.Tables("SalesOrderDetail")
Dim query = _
From order In orders.AsEnumerable() _
Where order.Field(Of Int16)("OrderQty") > 2 And _
order.Field(Of Int16)("OrderQty") < 6 _
Select order
Dim view As DataView = query.AsDataView()
bindingSource1.DataSource = view
The following example creates a DataView from a query for orders placed after June 6, 2001:
=====================================================
Dim orders As DataTable = dataSet.Tables("SalesOrderHeader")
Dim query = _
From order In orders.AsEnumerable() _
Where order.Field(Of DateTime)("OrderDate") > New DateTime(2002, 6, 1) _
Select order
Dim view As DataView = query.AsDataView()
bindingSource1.DataSource = view
The following example uses the SoundEx algorithm to find contacts whose last name is similar to "Zhu". The SoundEx algorithm is implemented in the SoundEx method.
=====================================================
Dim contacts As DataTable = dataSet.Tables("Contact")
Dim soundExCode As String = SoundEx("Zhu")
Dim query = _
From contact In contacts.AsEnumerable() _
Where SoundEx(contact.Field(Of String)("LastName")) = soundExCode _
Select contact
=====================================================
Dim view As DataView = query.AsDataView()
bindingSource1.DataSource = view
dataGridView1.AutoResizeColumns()
Using the RowFilter Property
=====================================================
Dim contacts As DataTable = dataSet.Tables("Contact")
Dim view As DataView = contacts.AsDataView()
view.RowFilter = "LastName='Zhu'"
bindingSource1.DataSource = view
dataGridView1.AutoResizeColumns()
Dim contacts As DataTable = dataSet.Tables("Contact")
Dim query = _
From contact In contacts.AsEnumerable() _
Where contact.Field(Of String)("LastName") = "Hernandez" _
Select contact
Dim view As DataView = query.AsDataView()
bindingSource1.DataSource = view
dataGridView1.AutoResizeColumns()
view.RowFilter = "LastName='Zhu'"
After a DataView has been created from a DataTable or LINQ to DataSet query, you can use the RowFilter property to specify subsets of rows based on their column values. The string-based and expression-based filters are mutually exclusive. Setting the RowFilter property will clear the filter expression inferred from the LINQ to DataSet query, and the filter expression cannot be reset.
The filter on a DataView can be cleared after filtering has been set using the RowFilter property. The filter on a DataView can be cleared in two different ways:
■Set the RowFilter property to null.
■Set the RowFilter property to an empty string.
=====================================================
Dim orders As DataTable = dataSet.Tables("SalesOrderHeader")
Dim query = _
From order In orders.AsEnumerable() _
Where order.Field(Of DateTime)("OrderDate") > New DateTime(2002, 11, 20) _
And order.Field(Of Decimal)("TotalDue") < New Decimal(60.0) _
Select order
Dim view As DataView = query.AsDataView()
bindingSource1.DataSource = view
view.RowFilter = Nothing
=====================================================
Dim contacts As DataTable = dataSet.Tables("Contact")
Dim view As DataView = contacts.AsDataView()
view.RowFilter = "LastName='Zhu'"
bindingSource1.DataSource = view
dataGridView1.AutoResizeColumns()
' Clear the row filter.
view.RowFilter = ""
LINQ Query Syntax versus Method Syntax (C#)
At compile time, query expressions are translated to something that the CLR does understand: method calls.
These methods are called the standard query operators, and they have names such as Where, Select, GroupBy, Join, Max, Average, and so on. You can call them directly by using method syntax instead of query syntax.
The following example shows a simple query expression and the semantically equivalent query written as a method-based query.
class QueryVMethodSyntax
{
static void Main()
{
int[] numbers = { 5, 10, 8, 3, 6, 12};
//Query syntax:
IEnumerable<int> numQuery1 =
from num in numbers
where num % 2 == 0
orderby num
select num;
//Method syntax:
IEnumerable<int> numQuery2 = numbers.Where(num => num % 2 == 0).OrderBy(n => n);
foreach (int i in numQuery1)
{
Console.Write(i + " ");
}
Console.WriteLine(System.Environment.NewLine);
foreach (int i in numQuery2)
{
Console.Write(i + " ");
}
// Keep the console open in debug mode.
Console.WriteLine(System.Environment.NewLine);
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
}
/*
Output:
6 8 10 12
6 8 10 12
*/
The output from the two examples is identical. You can see that the type of the query variable is the same in both forms: IEnumerable<T>.
If you are familiar with the generic IEnumerable<T> interface, you know that it does not have a Where method. However, if you invoke the IntelliSense completion list in the Visual Studio IDE, you will see not only a Where method, but many other methods such as Select, SelectMany, Join, and Orderby. These are all the standard query operators.
Although it looks as if IEnumerable<T> has been redefined to include these additional methods, in fact this is not the case. The standard query operators are implemented as a new kind of method called extension methods. Extensions methods "extend" an existing type; they can be called as if they were instance methods on the type. The standard query operators extend IEnumerable<T> and that is why you can write numbers.Where(...).
These methods are called the standard query operators, and they have names such as Where, Select, GroupBy, Join, Max, Average, and so on. You can call them directly by using method syntax instead of query syntax.
The following example shows a simple query expression and the semantically equivalent query written as a method-based query.
class QueryVMethodSyntax
{
static void Main()
{
int[] numbers = { 5, 10, 8, 3, 6, 12};
//Query syntax:
IEnumerable<int> numQuery1 =
from num in numbers
where num % 2 == 0
orderby num
select num;
//Method syntax:
IEnumerable<int> numQuery2 = numbers.Where(num => num % 2 == 0).OrderBy(n => n);
foreach (int i in numQuery1)
{
Console.Write(i + " ");
}
Console.WriteLine(System.Environment.NewLine);
foreach (int i in numQuery2)
{
Console.Write(i + " ");
}
// Keep the console open in debug mode.
Console.WriteLine(System.Environment.NewLine);
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
}
/*
Output:
6 8 10 12
6 8 10 12
*/
The output from the two examples is identical. You can see that the type of the query variable is the same in both forms: IEnumerable<T>.
If you are familiar with the generic IEnumerable<T> interface, you know that it does not have a Where method. However, if you invoke the IntelliSense completion list in the Visual Studio IDE, you will see not only a Where method, but many other methods such as Select, SelectMany, Join, and Orderby. These are all the standard query operators.
Although it looks as if IEnumerable<T> has been redefined to include these additional methods, in fact this is not the case. The standard query operators are implemented as a new kind of method called extension methods. Extensions methods "extend" an existing type; they can be called as if they were instance methods on the type. The standard query operators extend IEnumerable<T> and that is why you can write numbers.Where(...).
Queries in LINQ to DataSet
A query is an expression that retrieves data from a data source. Queries are usually expressed in a specialized query language, such as SQL for relational databases and XQuery for XML. Therefore, developers have had to learn a new query language for each type of data source or data format that they query. Language-Integrated Query (LINQ) offers a simpler, consistent model for working with data across various kinds of data sources and formats. In a LINQ query, you always work with programming objects.
A LINQ query operation consists of three actions: obtain the data source or sources, create the query, and execute the query.
In LINQ, a query is stored in a variable. If the query is designed to return a sequence of values, the query variable itself must be a enumerable type. This query variable takes no action and returns no data; it only stores the query information. After you create a query you must execute that query to retrieve any data.
In contrast to deferred queries, which return a sequence of values, queries that return a singleton value are executed immediately. Some examples of singleton queries are Count, Max, Average, and First. These execute immediately because the query results are required to calculate the singleton result. For example, in order to find the average of the query results the query must be executed so that the averaging function has input data to work with. You can also use the ToList(Of TSource) or ToArray(Of TSource) methods on a query to force immediate execution of a query that does not produce a singleton value. These techniques to force immediate execution can be useful when you want to cache the results of a query. For more information about deferred and immediate query execution, see Getting Started with LINQ.
LINQ to DataSet queries can be formulated in two different syntaxes: query expression syntax and method-based query syntax.
==========================================================
Query Expression Syntax
By using query expression syntax, you can perform even complex filtering, ordering, and grouping operations on data sources with minimal code.
Query expression syntax is new in C# 3.0 and Visual Basic 2008.
// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable products = ds.Tables["Product"];
IEnumerable<DataRow> query =
from product in products.AsEnumerable()
select product;
Console.WriteLine("Product Names:");
foreach (DataRow p in query)
{
Console.WriteLine(p.Field<string>("Name"));
}
==========================================================
Method-Based Query Syntax
The method-based query syntax is a sequence of direct method calls to LINQ operator methods,
passing lambda expressions as the parameters
// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable products = ds.Tables["Product"];
var query = products.AsEnumerable().
Select(product => new
{
ProductName = product.Field<string>("Name"),
ProductNumber = product.Field<string>("ProductNumber"),
Price = product.Field<decimal>("ListPrice")
});
Console.WriteLine("Product Info:");
foreach (var productInfo in query)
{
Console.WriteLine("Product name: {0} Product number: {1} List price: ${2} ",
productInfo.ProductName, productInfo.ProductNumber, productInfo.Price);
}
==========================================================
Composing Queries
As mentioned earlier in this topic, the query variable itself only stores the query commands when the query is designed to return a sequence of values. If the query does not contain a method that will cause immediate execution, the actual execution of the query is deferred until you iterate over the query variable in a foreach or For Each loop. Deferred execution enables multiple queries to be combined or a query to be extended. When a query is extended, it is modified to include the new operations, and the eventual execution will reflect the changes. In the following example, the first query returns all the products. The second query extends the first by using Where to return all the products of size "L":
// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable products = ds.Tables["Product"];
IEnumerable<DataRow> productsQuery =
from product in products.AsEnumerable()
select product;
IEnumerable<DataRow> largeProducts =
productsQuery.Where(p => p.Field<string>("Size") == "L");
Console.WriteLine("Products of size 'L':");
foreach (DataRow product in largeProducts)
{
Console.WriteLine(product.Field<string>("Name"));
}
After a query has been executed, no additional queries can be composed, and all subsequent queries will use the in-memory LINQ operators. Query execution will occur when you iterate over the query variable in a foreach or For Each statement, or by a call to one of the LINQ conversion operators that cause immediate execution.
These operators include the following: ToList<TSource>, ToArray<TSource>, ToLookup, and ToDictionary.
In the following example, the first query returns all the products ordered by list price. The ToArray<TSource> method is used to force immediate query execution:
// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable products = ds.Tables["Product"];
IEnumerable<DataRow> query =
from product in products.AsEnumerable()
orderby product.Field<Decimal>("ListPrice") descending
select product;
// Force immediate execution of the query.
IEnumerable<DataRow> productsArray = query.ToArray();
Console.WriteLine("Every price from highest to lowest:");
foreach (DataRow prod in productsArray)
{
Console.WriteLine(prod.Field<Decimal>("ListPrice"));
}
ref: http://msdn.microsoft.com/en-us/library/bb397947.aspx
A LINQ query operation consists of three actions: obtain the data source or sources, create the query, and execute the query.
In LINQ, a query is stored in a variable. If the query is designed to return a sequence of values, the query variable itself must be a enumerable type. This query variable takes no action and returns no data; it only stores the query information. After you create a query you must execute that query to retrieve any data.
In contrast to deferred queries, which return a sequence of values, queries that return a singleton value are executed immediately. Some examples of singleton queries are Count, Max, Average, and First. These execute immediately because the query results are required to calculate the singleton result. For example, in order to find the average of the query results the query must be executed so that the averaging function has input data to work with. You can also use the ToList(Of TSource) or ToArray(Of TSource) methods on a query to force immediate execution of a query that does not produce a singleton value. These techniques to force immediate execution can be useful when you want to cache the results of a query. For more information about deferred and immediate query execution, see Getting Started with LINQ.
LINQ to DataSet queries can be formulated in two different syntaxes: query expression syntax and method-based query syntax.
==========================================================
Query Expression Syntax
By using query expression syntax, you can perform even complex filtering, ordering, and grouping operations on data sources with minimal code.
Query expression syntax is new in C# 3.0 and Visual Basic 2008.
// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable products = ds.Tables["Product"];
IEnumerable<DataRow> query =
from product in products.AsEnumerable()
select product;
Console.WriteLine("Product Names:");
foreach (DataRow p in query)
{
Console.WriteLine(p.Field<string>("Name"));
}
==========================================================
Method-Based Query Syntax
The method-based query syntax is a sequence of direct method calls to LINQ operator methods,
passing lambda expressions as the parameters
// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable products = ds.Tables["Product"];
var query = products.AsEnumerable().
Select(product => new
{
ProductName = product.Field<string>("Name"),
ProductNumber = product.Field<string>("ProductNumber"),
Price = product.Field<decimal>("ListPrice")
});
Console.WriteLine("Product Info:");
foreach (var productInfo in query)
{
Console.WriteLine("Product name: {0} Product number: {1} List price: ${2} ",
productInfo.ProductName, productInfo.ProductNumber, productInfo.Price);
}
==========================================================
Composing Queries
As mentioned earlier in this topic, the query variable itself only stores the query commands when the query is designed to return a sequence of values. If the query does not contain a method that will cause immediate execution, the actual execution of the query is deferred until you iterate over the query variable in a foreach or For Each loop. Deferred execution enables multiple queries to be combined or a query to be extended. When a query is extended, it is modified to include the new operations, and the eventual execution will reflect the changes. In the following example, the first query returns all the products. The second query extends the first by using Where to return all the products of size "L":
// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable products = ds.Tables["Product"];
IEnumerable<DataRow> productsQuery =
from product in products.AsEnumerable()
select product;
IEnumerable<DataRow> largeProducts =
productsQuery.Where(p => p.Field<string>("Size") == "L");
Console.WriteLine("Products of size 'L':");
foreach (DataRow product in largeProducts)
{
Console.WriteLine(product.Field<string>("Name"));
}
After a query has been executed, no additional queries can be composed, and all subsequent queries will use the in-memory LINQ operators. Query execution will occur when you iterate over the query variable in a foreach or For Each statement, or by a call to one of the LINQ conversion operators that cause immediate execution.
These operators include the following: ToList<TSource>, ToArray<TSource>, ToLookup, and ToDictionary.
In the following example, the first query returns all the products ordered by list price. The ToArray<TSource> method is used to force immediate query execution:
// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable products = ds.Tables["Product"];
IEnumerable<DataRow> query =
from product in products.AsEnumerable()
orderby product.Field<Decimal>("ListPrice") descending
select product;
// Force immediate execution of the query.
IEnumerable<DataRow> productsArray = query.ToArray();
Console.WriteLine("Every price from highest to lowest:");
foreach (DataRow prod in productsArray)
{
Console.WriteLine(prod.Field<Decimal>("ListPrice"));
}
ref: http://msdn.microsoft.com/en-us/library/bb397947.aspx
Lambda Expressions(operator of " => ") (C# Programming Guide)
A lambda expression is an anonymous function that can contain expressions and statements,
and can be used to create delegates or expression tree types.
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." This expression can be assigned to a delegate type as follows:
delegate int del(int i);
static void Main(string[] args)
{
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25
}
==========================================================
Expression Lambdas
A lambda expression with an expression on the right side is called an expression lambda.
Expression lambdas are used extensively in the construction of Expression Trees (C# and Visual Basic).
An expression lambda returns the result of the expression and takes the following basic form:
(input parameters) => expression
The parentheses are optional only if the lambda has one input parameter;
otherwise they are required. Two or more input parameters are separated by commas enclosed in parentheses:
(x, y) => x == y
Sometimes it is difficult or impossible for the compiler to infer the input types. When this occurs,
you can specify the types explicitly as shown in the following example:
(int x, string s) => s.Length > x
Specify zero input parameters with empty parentheses:
() => SomeMethod()
==========================================================
Statement Lambdas
A statement lambda resembles an expression lambda except that the statement(s) is enclosed in braces:
(input parameters) => {statement;}
The body of a statement lambda can consist of any number of statements; however, in practice there are typically no more than two or three.
delegate void TestDelegate(string s);
…
TestDelegate myDel = n => { string s = n + " " + "World"; Console.WriteLine(s); };
myDel("Hello");
==========================================================
Lambdas with the Standard Query Operators
Many Standard query operators have an input parameter whose type is one of the Func<T, TResult> family of generic delegates. The Func<T, TResult> delegates use type parameters to define the number and type of input parameters, and the return type of the delegate. Func delegates are very useful for encapsulating user-defined expressions that are applied to each element in a set of source data. For example, consider the following delegate type:
public delegate TResult Func<TArg0, TResult>(TArg0 arg0)
The delegate can be instantiated as Func<int,bool> myFunc where int is an input parameter and bool is the return value. The return value is always specified in the last type parameter. Func<int, string, bool> defines a delegate with two input parameters, int and string, and a return type of bool. The following Func delegate, when it is invoked, will return true or false to indicate whether the input parameter is equal to 5:
Func<int, bool> myFunc = (x => x == 5);
bool result = myFunc(4); // returns false of course
You can also supply a lambda expression when the argument type is an Expression<Func>, for example in the standard query operators that are defined in System.Linq.Queryable. When you specify an Expression<Func> argument, the lambda will be compiled to an expression tree.
A standard query operator, the Count method, is shown here:
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int oddNumbers = numbers.Count(n => n % 2 == 1);
This example shows how to specify multiple input parameters by enclosing them in parentheses.
The method returns all the elements in the numbers array until a number is encountered
whose value is less than its position. Do not confuse the lambda operator (=>) with the greater than
or equal operator (>=).
var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);
==========================================================
Type Inference in Lambdas
When writing lambdas, you often do not have to specify a type for the input parameters because the compiler can infer the type based on the lambda body, the underlying delegate type, and other factors as described in the C# Language Specification. For most of the standard query operators, the first input is the type of the elements in the source sequence. So if you are querying an IEnumerable<Customer>, then the input variable is inferred to be a Customer object, which means you have access to its methods and properties:
customers.Where(c => c.City == "London");
The general rules for lambdas are as follows:
■The lambda must contain the same number of parameters as the delegate type.
■Each input parameter in the lambda must be implicitly convertible to its corresponding delegate parameter.
■The return value of the lambda (if any) must be implicitly convertible to the delegate's return type.
==========================================================
Variable Scope in Lambda Expressions
Lambdas can refer to outer variables that are in scope in the enclosing method or type in which the lambda is defined. Variables that are captured in this manner are stored for use in the lambda expression even if variables would otherwise go out of scope and be garbage collected. An outer variable must be definitely assigned before it can be consumed in a lambda expression. The following example demonstrates these rules:
delegate bool D();
delegate bool D2(int i);
class Test
{
D del;
D2 del2;
public void TestMethod(int input)
{
int j = 0;
// Initialize the delegates with lambda expressions.
// Note access to 2 outer variables.
// del will be invoked within this method.
del = () => { j = 10; return j > input; };
// del2 will be invoked after TestMethod goes out of scope.
del2 = (x) => {return x == j; };
// Demonstrate value of j:
// Output: j = 0
// The delegate has not been invoked yet.
Console.WriteLine("j = {0}", j); // Invoke the delegate.
bool boolResult = del();
// Output: j = 10 b = True
Console.WriteLine("j = {0}. b = {1}", j, boolResult);
}
static void Main()
{
Test test = new Test();
test.TestMethod(5);
// Prove that del2 still has a copy of
// local variable j from TestMethod.
bool result = test.del2(10);
// Output: True
Console.WriteLine(result);
Console.ReadKey();
}
}
The following rules apply to variable scope in lambda expressions:
■A variable that is captured will not be garbage-collected until the delegate that references it goes out of scope.
■Variables introduced within a lambda expression are not visible in the outer method.
■A lambda expression cannot directly capture a ref or out parameter from an enclosing method.
■A return statement in a lambda expression does not cause the enclosing method to return.
■A lambda expression cannot contain a goto statement, break statement, or continue statement
whose target is outside the body or in the body of a contained anonymous function.
ref: http://msdn.microsoft.com/en-us/library/bb397687.aspx
and can be used to create delegates or expression tree types.
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." This expression can be assigned to a delegate type as follows:
delegate int del(int i);
static void Main(string[] args)
{
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25
}
==========================================================
Expression Lambdas
A lambda expression with an expression on the right side is called an expression lambda.
Expression lambdas are used extensively in the construction of Expression Trees (C# and Visual Basic).
An expression lambda returns the result of the expression and takes the following basic form:
(input parameters) => expression
The parentheses are optional only if the lambda has one input parameter;
otherwise they are required. Two or more input parameters are separated by commas enclosed in parentheses:
(x, y) => x == y
Sometimes it is difficult or impossible for the compiler to infer the input types. When this occurs,
you can specify the types explicitly as shown in the following example:
(int x, string s) => s.Length > x
Specify zero input parameters with empty parentheses:
() => SomeMethod()
==========================================================
Statement Lambdas
A statement lambda resembles an expression lambda except that the statement(s) is enclosed in braces:
(input parameters) => {statement;}
The body of a statement lambda can consist of any number of statements; however, in practice there are typically no more than two or three.
delegate void TestDelegate(string s);
…
TestDelegate myDel = n => { string s = n + " " + "World"; Console.WriteLine(s); };
myDel("Hello");
==========================================================
Lambdas with the Standard Query Operators
Many Standard query operators have an input parameter whose type is one of the Func<T, TResult> family of generic delegates. The Func<T, TResult> delegates use type parameters to define the number and type of input parameters, and the return type of the delegate. Func delegates are very useful for encapsulating user-defined expressions that are applied to each element in a set of source data. For example, consider the following delegate type:
public delegate TResult Func<TArg0, TResult>(TArg0 arg0)
The delegate can be instantiated as Func<int,bool> myFunc where int is an input parameter and bool is the return value. The return value is always specified in the last type parameter. Func<int, string, bool> defines a delegate with two input parameters, int and string, and a return type of bool. The following Func delegate, when it is invoked, will return true or false to indicate whether the input parameter is equal to 5:
Func<int, bool> myFunc = (x => x == 5);
bool result = myFunc(4); // returns false of course
You can also supply a lambda expression when the argument type is an Expression<Func>, for example in the standard query operators that are defined in System.Linq.Queryable. When you specify an Expression<Func> argument, the lambda will be compiled to an expression tree.
A standard query operator, the Count method, is shown here:
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int oddNumbers = numbers.Count(n => n % 2 == 1);
This example shows how to specify multiple input parameters by enclosing them in parentheses.
The method returns all the elements in the numbers array until a number is encountered
whose value is less than its position. Do not confuse the lambda operator (=>) with the greater than
or equal operator (>=).
var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);
==========================================================
Type Inference in Lambdas
When writing lambdas, you often do not have to specify a type for the input parameters because the compiler can infer the type based on the lambda body, the underlying delegate type, and other factors as described in the C# Language Specification. For most of the standard query operators, the first input is the type of the elements in the source sequence. So if you are querying an IEnumerable<Customer>, then the input variable is inferred to be a Customer object, which means you have access to its methods and properties:
customers.Where(c => c.City == "London");
The general rules for lambdas are as follows:
■The lambda must contain the same number of parameters as the delegate type.
■Each input parameter in the lambda must be implicitly convertible to its corresponding delegate parameter.
■The return value of the lambda (if any) must be implicitly convertible to the delegate's return type.
==========================================================
Variable Scope in Lambda Expressions
Lambdas can refer to outer variables that are in scope in the enclosing method or type in which the lambda is defined. Variables that are captured in this manner are stored for use in the lambda expression even if variables would otherwise go out of scope and be garbage collected. An outer variable must be definitely assigned before it can be consumed in a lambda expression. The following example demonstrates these rules:
delegate bool D();
delegate bool D2(int i);
class Test
{
D del;
D2 del2;
public void TestMethod(int input)
{
int j = 0;
// Initialize the delegates with lambda expressions.
// Note access to 2 outer variables.
// del will be invoked within this method.
del = () => { j = 10; return j > input; };
// del2 will be invoked after TestMethod goes out of scope.
del2 = (x) => {return x == j; };
// Demonstrate value of j:
// Output: j = 0
// The delegate has not been invoked yet.
Console.WriteLine("j = {0}", j); // Invoke the delegate.
bool boolResult = del();
// Output: j = 10 b = True
Console.WriteLine("j = {0}. b = {1}", j, boolResult);
}
static void Main()
{
Test test = new Test();
test.TestMethod(5);
// Prove that del2 still has a copy of
// local variable j from TestMethod.
bool result = test.del2(10);
// Output: True
Console.WriteLine(result);
Console.ReadKey();
}
}
The following rules apply to variable scope in lambda expressions:
■A variable that is captured will not be garbage-collected until the delegate that references it goes out of scope.
■Variables introduced within a lambda expression are not visible in the outer method.
■A lambda expression cannot directly capture a ref or out parameter from an enclosing method.
■A return statement in a lambda expression does not cause the enclosing method to return.
■A lambda expression cannot contain a goto statement, break statement, or continue statement
whose target is outside the body or in the body of a contained anonymous function.
ref: http://msdn.microsoft.com/en-us/library/bb397687.aspx
2010年12月10日星期五
订阅:
博文 (Atom)