C #3.0 BASIC Language enhancements

Source: Internet
Author: User
Introduction to the LINQ project and establishment of the Development Environment

In May September, Microsoft launched a new technology called the "LINQ Project", which is used to integrate data query functions in the. NET language. You can get a technical preview of linqitem from http://msdn.microsoft.com/netframework/future/. it includes a large number of articles (in English), C #3.0, and VB 9.0 compilers.

Language Integrated Query is a language integrated query ". Based on. net Framework 2.0. Through language improvement, you can directly query the data source by constructing SQL-like statements in the language, data sources that can be queried can be extended from basic ordered structures (such as arrays and linked lists) to relational databases (currently SQL Server, and I believe it can be extended to almost all relational databases in the future) and XML.

C #3.0 is the version of the C # language after another upgrade. It is the first to implement the concept of LINQ. VB 9.0 is also implemented in the same way. From the URL above, you can find the technical preview version of the compiler in two languages. In this article, we will focus on C #3.0 to discuss how to build the development environment and improve the language. Download an installation package named "LINQ preview. MSI" (which may also be different). You can double-click it to install it like other software. This installation package provides plug-ins (project templates) and C # compilers for Visual Studio 2005 beta 2 and later versions and Visual C #2005 beta 2, the IL code generated by the compiler can be directly stored in.. NET Framework 2.0. After the preview version is installed, under the Visual C # node in the project type list in the new project dialog box, we can see an entry of the LINQ preview, you can also select some desktop project templates from the project templates on the right (web projects are not supported by LINQ currently), as shown in:

Figure 1-create a project after Visual Studio 2005 is installed

As long as you select the project template in LINQ, you can write the C #2005 Application in Visual Studio 3.0 just like writing other applications, during compilation, the IDE automatically selects the C #3.0 compiler for us.

Now we can start to write the C #3.0 application. In the subsequent sections, I will explain the language enhancements brought about by C #3.0. It is worth noting that this article is one of a series of articles, which consists of three parts. This article is the first part about C #3.0 BASIC Language enhancements. These language enhancements are the basis of the other two parts. The second part describes the lambda expressions in C #3.0, this is a natural evolutionary form of anonymous methods. It not only reflects expressions as executable methods (delegates ), expressions can also be reflected in the data structure that can be operated at runtime-expression tree; the last part is about the most core and exciting content in the LINQ project-Query expressions, this is the implementation form of LINQ in C. At the same time, the. NET Framework base class library is expanded for SQL queries and XML queries, respectively known as dlinq and xlinq. These contents will be described in other series of articles.

In the process described in this article, we only provide short code segments rather than complete code. However, these code segments are extracted from the complete, correctly compiled, and running code, which can be downloaded from here, the complete code is introduced in part 1 of this Article.

Well, there is too much nonsense. Let's enter the wonderful world of C #3.0.

  Declarations with implicit types

In a declaration statement with an initiator, the type of the variable to be declared is obvious-consistent with the result type of the initialization expression. In this case, the New Keyword VaR can be used in C #3.0 to replace the declared type, and the compiler can deduce the type of the Variable Based on the initialization expression.

VaR I = 5; // int
VaR d = 9.0; // double
VaR S = "hello"; // string
VaR A = new int [] {1, 2, 3, 4, 5}; // int []

Console. writeline ("type of variable <I >:{ 0}", I. GetType ());
Console. writeline ("type of variable <D >:{ 0}", D. GetType ());
Console. writeline ("type of variable <s >:{ 0}", S. GetType ());
Console. writeline ("type of variable <a >:{ 0}", A. GetType ());

The above Code complies with the syntax rules in C #3.0. The first four lines of code use an implicit declaration; the last four lines of code are used to verify whether each variable has the correct type at runtime. If you run this code in Visual Studio 2005 (to see the results, use Ctrl + F5 to compile and start the program), you will get the following results:

Type of variable <I>: system. int32
Type of variable <D>: system. Double
Type of variable <S>: system. String
Type of variable <A>: system. int32 []

This indicates that the compiler has correctly deduced the type of each variable during compilation and embedded it into the Assembly metadata.

There are two restrictions: one is that declarations with implicit types can only be applied to local variables, and the other is that such declarations must have an initiatator (that is, the equal sign and the following expression ). If we attempt to declare a domain with an implicit type in a class, a compilation error occurs: Invalid token 'var' in class, struct, or interface member declaration; if the initialization tool does not appear in the declaration, another compilation error occurs: '=' expected.

In addition to local variables, an array with a block scope can also be declared with an implicit type. For example:

VaR IA = new [] {1, 2, 3, 4, 5}; // int []
VaR da = new [] {1.1, 2, 3, 4, 5}; // double []
VaR SA = new [] {"hello", "world"}; // string []

Console. writeline ("type of array <Ia >:{ 0}", IA. GetType ());
Console. writeline ("type of array <da >:{ 0}", da. GetType ());
Console. writeline ("type of array <SA >:{ 0}", SA. GetType ());

In the array declaration in the preceding example, the type name is omitted between the new operator and a pair of square brackets indicating the array declaration, but this still complies with the syntax rules in C #3.0. The compiler will infer the type of the array by the value type in the member list. Compile and run the preceding example to get the following output:

Type of array <Ia>: system. int32 []
Type of array <da>: system. Double []
Type of array <Sa>: system. String []

In addition to the same constraints as local variables with implicit types, arrays with implicit types must also be exclusive to the rule that all values in the member list must be compatible. That is to say, such a value must exist in the member list so that other values can be implicitly converted to the type of the value. Therefore, the following statement does not comply with the syntax rules:

VaR AA = new [] {1, "hello", 2.0, "world "};

If you try to compile the above Code, you will get a compilation error: No array type can be inferred from the initializers. This is because the compiler cannot deduce the array type based on the values in the member list.

In fact, although implicit declarations facilitate the compilation of traditional declarations, the true purpose of introducing such declarations is not that, in order to allow local variables and arrays to access such a new language structure: anonymous type.

Anonymous type

In many cases, we need an object that can temporarily store a batch of associated data; or in some cases, we are interested in the shape of only one object (such as the attribute name and type. For example, in the book we mentioned earlier, when it is put together with other products for query, we may only be interested in its name and price, you also want to put these two attributes in another temporary object for future use. At this time, we only focus on the temporary object with the name and price of the sexy interest, as to what type it is irrelevant. However, to make such an object exist, we have to write a lot of "sample code" for this insignificant type, instead of defining a class such as bookasgood, it is nothing more than a private domain like m_name and m_price, and a public read/write method named name and price.

In C #3.0, we do not need to waste time on these irrelevant types. By using the "anonymous type", you only need to use a new expression without a type name when you need such an object and initialize it with the object initiator mentioned above. For example:

VaR b1 = new {name = "the first sample book", price = 88.0f };
VaR b2 = new {price = 25366f, name = "the second sample book "};
VaR B3 = new {name = "the third sample book", price = 35.00f };

Console. writeline (b1.gettype ());
Console. writeline (b2.gettype ());
Console. writeline (b3.gettype ());

First, the first three rows declare and initialize three objects of the anonymous type, both of which have the public read/write attribute name and price. We can see that the connection type of the attribute of the anonymous type is eliminated, and it is entirely inferred by the compiler based on the initialization expression of the corresponding attribute. These three lines are called "anonymous object initiators". When the compiler encounters such a statement, first, a type with an internal name will be created (the so-called "Anonymous" is only anonymous at the source code level, and such a name will still exist in the final compiled metadata ), this type has two read/write attributes, and two private fields are used to store the attribute values. Then, like the object initializer, the compiler generates the object declaration code and assigns values to each attribute in turn.

The last three lines of the code above are used to check the type of the anonymous type at runtime. If you try to compile and run the above Code, the output is similar to the following:

Lover_p.csharp3samples.ex03.program + <projection> F _ 0
Lover_p.csharp3samples.ex03.program + <projection> F _ 1
Lover_p.csharp3samples.ex03.program + <projection> F _ 0

This indicates that the compiler indeed creates an actual type for an anonymous type object and this type is not accessible in the code, because the type name does not comply with the C # naming rules (including invalid characters such as +, <,> ).

In addition, we also found an interesting phenomenon. Because B1 and B2 have the same attribute sequence as the inferred type during initialization, their runtime types are the same; b2 has different runtime types because the attribute order is different from the other two objects. The following code verifies this fact:

// Correct value assignment. B1 and B3 have the same type
B1 = B3;

// Incorrect value assignment. The B1 and B2 types are different.
B1 = B2;

If you try to compile this code, we will get a compilation error for the second value: cannot implicitly convert type 'lover _ p. csharp3samples. ex03.program. <projection> F _ 1 'to 'lover _ p. csharp3samples. ex03.program. <projection> F _ 0 '.

This is actually an inherent feature of the C #3.0 compiler. In the same set of programs, the compiler will generate a unique type for an anonymous type object with identical order and type of attributes. Once the order or type of an attribute is different, the compiler generates different types. In addition, even if the order and type of the attributes appear in the two sets are the same, the compiler may generate different types. Therefore, objects with anonymous types cannot be accessed across sets.

Extension Method

An extension method is a special static method, which is defined in a static class, but can be called on objects of other classes as if the instance method is called. Therefore, with the extension method, we can expand the function of a type without modifying a type. At the same time, you can also implement similar functions in some similar types in the same class to facilitate reading and maintenance.

In addition, the introduction of extension methods is not simply to extend existing types, but there are still some restrictions on the use of extension methods (which will be discussed later ). The larger significance of the extension method is that it lays the foundation for the implementation of the Query expressions, query expression modes, and standard query operators to be introduced in the future. These implementations are the core of the LINQ project.

1. Define and call extension methods

The extension method is similar to the definition method of a general static method. The only difference is that the keyword "this" must be added before the first parameter as the modifier. At the same time, the type of the first parameter also determines the type that can be extended by the extension method.

To introduce the definition and usage of the extension method, we first define the following simple class as the extension object:

Class sampleclass
{
Int m_val = 10;

Public int Val {get {return m_val;} set {m_val = value ;}}

Public void func ()
{
Console. writeline ("Hey! I'm myself, and my value is {0}. ", m_val );
}
}

This class has a public read/write attribute Val, and a private domain m_val is used to store the value of this attribute. In addition, this class also has a public method func, which is used to display row information on the screen, indicating that the method has been called.

Then, we define a static type sampleextensions (this name is random and will be used only when the extension method is called as a common static method ), define an extension method exfunc used to expand the sampleclass type:

Static class sampleextensions
{
Public static void exfunc (this sampleclass S)
{
Console. writeline ("Aha! I'm going to modify the sampleclass! ");
S. Val = 20;
S. func ();
}
}

Note that this modifier is added before the type of the first parameter (also the only parameter) of this method, which indicates that this method is used to extend the sampleclass type, that is to say, you can call the exfunc Method on an object of the sampleclass type as if you were calling the instance method. This method first tells the user that it is being called, then modifies the attributes of an object of the sampleclass type, and calls its instance method.

Next, we create an instance of the sampleclass type in the main method, and try to call its instance method and the extension method defined above:

Sampleclass S = new sampleclass ();

Console. writeline ("calling the instance method :");
S. func ();
Console. writeline ();

Console. writeline ("calling the extension method :");
S. exfunc ();

We can see that the call form for exfunc is exactly the same as that for the func method. However, we can clearly understand from the above Type Definitions, func is an instance method defined in the sampleclass type, while exfunc is an extension (static) method defined in the sampleextensions type. Compile and run the above code to get the following results:

Calling the instance method:
Hey! I'm myself, and my value is 10.

Calling the extension method:
Aha! I'm going to modify the sampleclass!
Hey! I'm myself, and my value is 20.

Of course, since the extension method is only a special case of the static method, we can also call the extension method as we call the general static method:

Sampleextensions. exfunc (s );

This will get the same result. In fact, the compiler translates the call to an extended method into a normal form of static method call before further compilation.

The extension method not only extends the types in the same assembly, but also extends the types in different assembly or even released assembly. Next, we will add an extension method in sampleextensions to extend the built-in type string of the. NET Framework. (This example is excerpted from the C #3.0 language specification, which is copyrighted by Microsoft .) :

Public static int toint32 (this string S)
{
Return int32.parse (s );
}

Then, we can easily convert a string to an integer as follows:

String sval = "20 ";
Console. writeline ("string '20' means INTEGER: {0}.", sval. toint32 ());

Run this code and you will get the following results:

String '20' means INTEGER: 20.

After a brief look at the. NET Framework documentation, we will find that the toint32 method is indeed not defined in the system. string type, which means our extension method is still effective in the. NET Framework built-in type.

 2. Import and permission of extension methods

We have discussed how to define and call an extension method in the same assembly. If an extension method is defined in another assembly, how can we use the functions provided by these extension methods? The fact is very simple. C #3.0 language specification stipulates that when we use the using statement to import a namespace, all anonymous methods defined in all static types in the namespace will be imported at the same time.

3. Heavy Selection

After reading the above introduction, we can easily find a problem: if the signature of an instance method in a type is equivalent to that of an extension method ("equivalent" here is because the extension method is different from the instance method in the same call form, if there is one more parameter indicating the extended type, that is, the first parameter with the this modifier), a conflict occurs when the method is called on the extended type object. This type of conflict is called the problem of heavy selection. C #3.0 the Language Specification extends the heavy-load choice, and the call to the extension method is also included in the scope of the heavy-load choice, and requires that the extension method has the lowest priority. That is to say, for a set of parameter lists of feature types and specific sequence, only when the method of the extended type cannot be matched, select the most suitable method from the extension method for calling.

Now, we add another extension method func for the above sampleextensions class to extend the sampleclass type:

Public static void func (this sampleclass S)
{
S. Val =-1;
Console. writeline ("Am I appearing? ");
}

If you call this extension method using the syntax of calling the instance method, the call form is exactly the same as calling the instance method func without parameters. Compile and run the original program again, and the output result is not changed. That is to say, this extension method is not called at all. The actually called method is the instance method func. Of course, there is no problem if you call this extension method as a normal static method.

In addition, if two static Classes define a static method with the same signature for the same type, the final static method has a higher priority; the static method defined in the same program has a higher priority than the extension method imported from other namespaces using the using statement. Finally, if the two namespaces contain extension methods with consistent signatures, the extended method in the namespace introduced at the end has a higher priority.

Introduction and summary of sample code

The code in this article includes a solution "csharp3sample1", which includes four projects: ex01 ~ Ex04, respectively corresponding to 1st ~ 4. Examples in this section. You can download the source code of this article from here. To run an example, right-click the corresponding project in the Solution Explorer window of Visual Studio 2005 and select the "set as startup project" menu item; then press Ctrl + F5 to run the example. We recommend that you press Ctrl + F5 instead of press F5 to run the example because it can be paused after the running is complete, easy to observe the results (for personal reasons, I do not want to add a console like this to the code. readline code to pause the running of the program ). In addition, you must install Visual Studio 2005 beta2 and LINQ preview correctly before running the code.

This article introduces the basic language enhancements in C #3.0 through a series of simple code that can be executed and can see the results-objects with implicit types and array declarations, objects and set initiators, anonymous type and extension method. And C #2.0 to C #1. different from X, C #3.0 enhances these languages not only to enhance and elegance of languages, but also to lay the foundation for implementing lambda expressions and Query expressions.

 

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.