C # Future Functions of programming languages

Source: Internet
Author: User
Tags microsoft c
Document directory
  • Microsoft C #
  • Potential future functions
  • Generate the latest generic class
  • Create and use generic
  • Advantages of generics
  • Generic support in other languages
Released on: 4/30/2003 | updated on: 6/25/2004

Prashant sridharan

Microsoft Corporation

Applicable to: Microsoft Visual C # (TM)

Summary: Microsoft Corporation is developing the next major version of C. This article introduces four main new features: Generic, iterative program, anonymous method, and local type.

Content on this page
Iteration Program
Anonymous Method
Local type
Compliant with standards
More information


C # is an innovative new programming language that skillfully integrates the most common industry language and the functions in the research language. While keeping the C # design philosophy unchanged, Microsoft introduces several potential new features in the C # language, improving developers' efficiency in terms of language structure.

Microsoft C #

Since the advent of C # In February 2001, many developers have begun to use the C # programming language to build software. Microsoft also uses C # to build several formal applications, including. NET Framework, MSN web attributes, and tablet pc sdk. Therefore, C # is a language suitable for building high-quality commercial software.

C # many features in the language are created based on the following four different design objectives:

Unified Type System and simplified usage of value type and reference type in C # language.

Build a component-based design by using XML annotations, features, attributes, events, and delegation.

With the unique features of C # Language (including secure pointer operations, overflow checks, etc.), a practical developer control function is created.

Build practical language structures such as foreach and using statements to improve developers' efficiency.

In the "Visual Studio for Yukon" version of C #, Microsoft plans to build a concise and practical syntax by combining a wide range of research languages with a variety of functions in industrial languages. These language functions include generics, iterative programs, anonymous methods, and local types.

Potential future functions

In fact, C #'s future innovative functions are mainly based on a unified type system, component-based development, developer control functions, and practical language structures. The following summarizes four major new features Microsoft plans to provide in the next major version of C. The design of these features has not yet been completed. Microsoft Corporation welcomes developers to comment on these features.

Back to Top


As projects become increasingly complex, programmers increasingly need a way to better reuse and customize their existing component-based software. To reuse advanced code in other languages, programmers usually use a function called "generic. C # will include a safe and efficient generic type, which is slightly different from the template in C ++ and the generic type proposed in Java in syntax, however, there is a big difference in implementation methods.

Generate the latest generic class

With the current C #, programmers can store data in basic object type instances to create a limited form of real generic. In C #, each object is inherited from the basic object type, and unified is added.. Net Type System boxing and unboxing functions, programmers can store the reference type and value type to object type variables. However, there are some performance defects in the conversion between the reference type, value type, and basic object type.

To illustrate this, the following code example creates a simple stack type, which contains two operations: "push" and "pop ". The Stack class stores its data in an array of object types. The push and pop methods use basic object types to accept and return data:

public class Stack{   private object[] items = new object[100];   public void Push(object data)   {      ...   }   public object Pop()   {      ...   }}

Then, you can press the custom type (such as the customer type) into the stack. However, if the program needs to retrieve data, it needs to explicitly convert the result of the POP method (Basic Object Type) to the customer type.

Stack s = new Stack();s.Push(new Customer());Customer c = (Customer) s.Pop();

If a value type (such as an integer) is passed to the push method, it is automatically converted to the reference type (this process is called packing) during the runtime ), store the data in the internal data structure. Similarly, if the program wants to retrieve a value type (such as an integer) from the stack, it needs to explicitly convert the object type obtained from the POP Method to the value type, this process is called unboxing:

Stack s = new Stack();s.Push(3);int i = (int) s.Pop();

The packing and unboxing operations between the value type and the reference type are very heavy.

In addition, the data types placed in the stack cannot be limited in the current implementation. In fact, you can first create a stack and then press the customer type into the stack. Then, you can use the same stack and try to pop up the data, and then convert it to another type, as shown in the following example:

Stack s = new Stack();s.Push(new Customer());Employee e = (Employee) s.Pop();

Although the previous code example mistakenly uses a single type of Stack class to be implemented, it should be regarded as an error, but it is actually legal code and will not cause any problems during compilation. However, during running, the program will fail due to the invalid conversion operation.

Create and use generic

Using Generics in C #, you can create efficient data structures dedicated to compilers Based on the types they use. After these so-called parameterized types are created, their internal algorithms remain unchanged, but their internal data types can change with the setting of end users.

To help developers save time for learning the language, the generic declaration method in C # is roughly the same as that in C ++. Programmers can create classes and structures in the usual way, and use angle brackets to mark (<and>) to specify type parameters. When using a class, you must replace each parameter with the actual type provided by the class user.

In the following example, a stack class is created, and a type parameter named itemtype is specified and declared in the angle brackets after such declaration. An instance of the generic Stack class accepts the type created for it and stores the data of this type locally, instead of converting between the created type and the basic object type. The itemtype parameter acts as a proxy until the type is specified during instantiation and used as an internal item array (that is, the parameter type of the push method and the return type of the POP method ):

public class Stack<ItemType>{   private ItemType[] items;   public void Push(ItemType data)   {      ...   }   public ItemType Pop()   {      ...   }}

When the program uses the Stack class as follows, you can specify the actual type used by the generic class. In this example, the angle brackets in the instantiation statement are used to mark the original Integer type as a parameter, indicating that the Stack class uses this type:

Stack<int> stack = new Stack<int>();stack.Push(3);int x = stack.Pop();

When this operation is performed, the program creates a new instance of the stack class, and each itemtype is replaced by an integer parameter provided. In fact, when a program uses the integer parameter to create a new instance of the stack class, the project array locally stored in the stack class will be an integer rather than an object. The program also eliminates the packing problem associated with pushing integers into the stack. In addition, when a program pops up a project from the stack, you do not need to explicitly convert it to the corresponding type, because the current specific instance of the stack class stores integers locally in its data structure.

To store other types of projects in the stack class, you must create a new instance of the stack class and specify the new type as a parameter. Suppose there is a simple customer type, and you want the program to use the stack object to store this type. To implement this operation, you only need to instantiate the Stack class and take the customer object as its type parameter to easily reuse the program code:

Stack<Customer> stack = new Stack<Customer>();stack.Push(new Customer());Customer c = stack.Pop();

Of course, if the program creates a stack class that uses the customer type as the parameter, it can only store the customer type in the stack. In fact, generics in C # have strict types, which means you cannot store integers in the stack, as shown in the following example:

Stack <customer> stack = new stack <customer> (); stack. push (new customer (); stack. push (3) // compile error customer C = stack. pop (); // No type conversion is required.
Advantages of generics

With generics, programmers only need to write, test, and deploy the code once, and can reuse the code for different data types. The first stack example provides this function, and the Second stack example allows applications to reuse code that has little impact on the performance of their applications. For value types, the first stack example has a high performance problem, while the second stack example completely eliminates this problem because it removes the boxing and downward type conversion.

In addition, the generic type is also checked during compilation. When a program uses the provided type parameter to instantiate a generic class, this type parameter can only be the type specified by the program in the class definition. For example, if the program creates a stack of the customer object type, it cannot push integers into the stack. By performing this operation forcibly, you can generate more reliable code.

In addition, compared with other strict type implementations, the generic C # implementation reduces the code expansion speed. Creating a set of types with generics can avoid creating specific variants of each class while maintaining operational performance advantages. For example, a program can create a parameterized Stack class without the need to create integerstack for storing integers, stringstack for storing strings, and mermerstack for storing customer types.

This increases the readability of the Code. By creating a stack class, the program can encapsulate all operations associated with a stack in a convenient class. Then, even though the customer type is stored in the stack, it is obvious that the program uses the stack data structure.

Multiple type parameters

Wildcard can use any number of parameter types. The preceding stack example only uses one type. Assume that you have created a simple dictionary class that stores values and keys. In a program, two parameters can be declared (separated by commas in the brackets of the class definition) to define a generic version of the dictionary class:

public class Dictionary<KeyType, ValType>{   public void Add(KeyType key, ValType val)   {      ...   }   public ValType this[KeyType key]   {      ...   }}

When using this dictionary class, you must provide multiple comma-separated parameters in the angle brackets of the instantiated statement, and provide the correct type parameters for the Add function and index generator:

Dictionary<int, Customer> dict = new Dictionary<int, Customer>();dict.Add(3, new Customer());Customer c = dict.Get[3];


Generally, a program is not limited to storing data based on a given type parameter, but often needs to use a member of the type parameter to execute statements in the program generic.

Why Constraints

Assume that in the add method of the dictionary class, you need to use the compareto method of the provided key to compare the project. For example:

public class Dictionary<KeyType, ValType>{   public void Add(KeyType key, ValType val)   {      ...      switch(key.CompareTo(x))      {      }      ...   }}

Unfortunately, as expected, the keytype parameter is generic during compilation. In this case, the compiler assumes that only operations applicable to basic object types (such as tostring) can be performed on key instances with the keytype parameter. The compiler displays a compilation error because the compareto method is not defined. However, the program can convert the key variable to an object that contains the compareto method, such as the icomparable interface. In the following example, the program explicitly converts the instance key of the keytype parameter type to the icomparable interface that can be compiled by the Program:

public class Dictionary<KeyType, ValType>{   public void Add(KeyType key, ValType val)   {      ...      switch(((IComparable) key).CompareTo(x))      {      }      ...   }}

However, if the dictionary class is instantiated immediately and the provided type parameter does not implement the icomparable interface, the program will encounter a runtime error, especially an invalidcastexception.

Declare Constraints

In C #, the program can provide a list of optional constraints for each type parameter declared in the generic class. Constraints indicate the requirements that must be met to construct a type into a generic type. You can use the where keyword to declare the constraint, which is followed by the "parameter-Requirement" pair. The "parameter" must be a parameter defined in the generic model, and the "requirement" must be a class or interface.

To meet the needs of using the compareto method in the dictionary class, the program can add constraints to the keytype parameter. The icomparable interface must be implemented for any type passed to the dictionary class as the first parameter, for example:

public class Dictionary<KeyType, ValType> where KeyType : IComparable{   public void Add(KeyType key, ValType val)   {      ...      switch(key.CompareTo(x))      {      }      ...   }}

In this way, the code will be checked during compilation to ensure that the icomparable interface is implemented every time the program uses a dictionary class as the type passed as the first parameter. In addition, the program no longer needs to explicitly convert the variable to the icomparable interface before calling the compareto method.

Multiple Constraints

For any given type parameter, the program can specify any number of interface constraints for it, but only one class constraint can be specified. Each new constraint is declared in the form of another parameter-requirement, and each constraint of the given generic type is separated by commas. The dictionary class in the following example contains two types of parameters: keytype and valtype. The keytype parameter has two interface constraints, while the valtype parameter has one class constraint:

public class Dictionary<KeyType, ValType> whereKeyType : IComparable,KeyType : IEnumerable,ValType : Customer{   public void Add(KeyType key, ValType val)   {      ...      switch(key.CompareTo(x))      {      }      ...   }}

Runtime generics

There is almost no difference between the compilation methods of generic classes and those of general classes. In fact, the compilation result is only metadata and intermediate language (IL ). Of course, to accept the types provided by users in the code, il should be parameterized. The usage of generic il varies depending on whether the type parameter is a value type or a reference type.

When the value type is used as a parameter to construct a generic type for the first time, the runtime replaces the corresponding location in Il with the provided parameter to create a specialized generic type. For each unique value type used as a parameter, a dedicated generic type is created at one time.

For example, assume that the program code declares a stack composed of integers:

Stack<int> stack;

In this case, a dedicated Stack class is generated during the runtime, and the corresponding parameters of this class are replaced with integers. Now, the generated dedicated Stack class will be used repeatedly at runtime no matter when the program code uses an integer stack. The following example creates two instances of an integer stack. Each instance is created using the code generated during the running of the integer Stack:

Stack<int> stackOne = new Stack<int>();Stack<int> stackTwo = new Stack<int>();

However, if another stack class is created elsewhere in the program code and different value types (such as long integer or user-defined structures) are used as their parameters, the runtime generates other forms of generics, and then replaces the long integer parameter in the corresponding location of Il. The advantage of creating a dedicated class for a generic type constructed using a value type is that it can achieve better performance. After all, each dedicated generic class contains a value type in "local", so no conversion is required.

Generic and reference types work in a slightly different way. When any reference type is used to construct a generic type for the first time, the runtime replaces the parameters in Il with object references to create a specialized generic type. Then, whenever the reference type is used as the type of the parameter instantiation construction, no matter what type is constructed, the previously created dedicated generic type will be reused during the runtime.

For example, assume that there are two reference types, the customer class and the order class, and then create a stack of the customer type:

Stack<Customer> customers;

At this time, a dedicated Stack class will be generated during the runtime. This class does not store data, but stores the reference of the subsequently filled object. Assume that the next line of code creates a stack of other reference types, called order:

Stack<Order> orders = new Stack<Order>();

Unlike the value type, instead of creating another dedicated Stack class for the order type, you create an instance for the dedicated Stack class and set the orders variable to reference it. For each object reference that replaces the type parameter, the memory space is allocated according to the size of the order type, and the pointer is set to reference this memory location. Assume that you subsequently encounter a line of code used to create a stack of the customer type:

customers = new Stack<Customer>();

Like the Stack class created using the order type, another instance of the dedicated Stack class is created, and the pointer contained in the class is set to reference the memory area of the customer type. Because different programs vary greatly in the number of reference types, therefore, the implementation of Generic C # reduces the number of reference types to the number of specialized classes created by the compiler for generic classes of reference types, greatly reducing the code expansion speed.

In addition, when a Generic C # class is instantiated using a type parameter (either a value type or a reference type), you can use reflection and the actual type for query at runtime, you can also determine its type parameters.

C #Differences between generics and Other implementations

There are significant differences between C ++ templates and C # generics. C # The generic type is compiled into Il, which intelligently creates the corresponding private type for each value type at runtime, while only one private type is created for the reference type; the C ++ template is actually a code expansion macro, which generates a special type for each type parameter provided to the template. Therefore, when the C ++ compiler encounters a template (such as an integer stack), it will extend the template code to the stack class and include the integer as the type of the class itself. Whether the type parameter is a value type or a reference type, if the linker is not specifically designed to reduce the code expansion speed, the C ++ compiler creates a dedicated class each time, this leads to a much higher code expansion speed than using C # generics.

In addition, the C ++ template cannot define constraints. The C ++ template can only use one member (which may or may not belong to a type parameter) and implicitly define constraints. If the member exists in the type parameter passed to the generic class, the program runs normally. Otherwise, the program fails and may return hidden error messages. C # generics can declare constraints and have strict types, so these potential errors do not exist.

Now, Sun Microsystems has added other generic types to the new Java language (the code name is "tiger. The implementation selected by Sun does not need to be modified by the Java Virtual Machine. Therefore, Sun is faced with the problem of how to implement generics On unmodified virtual machines.

The proposed Java implementation uses a syntax similar to the template in C ++ and the generic syntax in C #, including type parameters and constraints. However, because the processing value type is different from the processing reference type, the unmodified Java virtual machine does not support the generic value type. Therefore, Java generics cannot be effectively executed. In fact, the Java compiler inserts an automatic downward type conversion from the specified constraint (if declared) or basic object type (if not declared) when it needs to return data. In addition, the Java compiler will generate a dedicated type at runtime, and then use it to instantiate any construction type. Finally, because the Java Virtual Machine itself does not support generics, it is impossible to determine the type parameters of the generic instance at runtime, and other purposes of reflection will be severely restricted.

Generic support in other languages

Microsoft aims to support the use and creation of generics in Visual J # (TM), Visual C ++, and Visual Basic. Although the time for implementing this feature in different languages is too late, all the other three languages of Microsoft will support generics. At the same time, the C # team is working to add relevant functions to the basic runtime of the generic model to lay the foundation for implementing multi-language support. Microsoft works closely with third-party language partners to ensure that generics are created and used in. Net-based languages.

Back to Top

Iteration Program

Iterative programs are constructed based on similar functions in the research language (such as Clu, sather, and Icon. Simply put, through iterative programs, the type can easily declare the foreach statement to iterate its elements.

Why iterative programs

Now, if the class needs to use the foreach loop structure to support iterative operations, they must implement the "enumerator mode ". For example, the compiler extends the foreach loop structure on the left to the while loop structure on the right:

List list = ...;foreach(object obj in list){DoSomething(obj);} Enumerator e = list.GetEnumerator();while(e.MoveNext()){   object obj = e.Current;   DoSomething(obj); 

It is worth noting that in order for the foreach loop to run properly, the List data structure (the iterated instance) must support the getenumerator function. After creating the list data structure, you must implement the getenumerator function to return the listenumerator object:

public class List{   internal object[] elements;   internal int count;   public ListEnumerator GetEnumerator()   {      return new ListEnumerator(this);   }}

The listenumerator object must not only implement the current attribute and movenext method, but also maintain its internal state so that the program can move to the next item every time the program executes the loop. This internal state machine is relatively simple for the List data structure, but for data structures that require recursive loops (such as binary trees), this state machine will be quite complex.

Since the implementation of this enumerator mode requires developers to invest a lot of effort and write a lot of code, C # contains a new structure, this allows the class to easily indicate the way in which the foreach loop iterates its content.

Define an iteration Program

Since an iteration program is a logical counterpart of the foreach loop structure, its definition is similar to a function: Use the foreach keyword with a pair of parentheses. In the following example, the program declares an iterator for the list type. The return type of the iteration program is determined by the user, but because the list class stores the object type internally, the return type of the following iteration program example is the object:

public class List{   internal object[] elements;   internal int count;   public object foreach()   {   }}

It is worth noting that after the enumerator mode is implemented, the program needs to maintain the internal state machine to track the position of the program in the data structure. The iterator has a built-in state machine. With the new yield keyword, the program can return the value to the foreach statement that calls the iteration program. When the foreach statement repeats and calls the iteration program again, the previous yield statement is executed. In the following example, the program generates three string types:

public class List{   internal object[] elements;   internal int count;   public string foreach()   {      yield "microsoft";      yield "corporation";      yield "developer division";   }}

In the following example, the foreach loop that calls this iteration program will be executed three times, each of which will receive strings in the order specified by the first three yield statements:

List list = new List();foreach(string s in list){Console.WriteLine(s);}

If you want the program to implement an iterator to traverse the elements in the list, you need to use foreach loop to modify this iterator so that it can traverse the element array and generate each item in the array in each iteration:

public class List{   internal object[] elements;   internal int count;   public object foreach()   {      foreach(object o in elements)      {         yield o;      }   }}

How iterative programs work

The iterator represents the program processing that implements the routine operations of the enumerator mode. C # The Compiler converts the code you write in an iteration program into the corresponding classes and code in the enumeration mode, without the need to create classes and create state machines. In this way, iterative programs significantly improve the efficiency of developers.

Back to Top

Anonymous Method

The anonymous method is another practical language structure that enables programmers to create code blocks that can be packed in a delegate and can be executed later. They are based on the concept of a language called a Lambda function and are similar to the corresponding language concepts in LISP and python.

Create delegate code

A delegate is an object that references a method. When a delegate is called, The referenced method is called. The following example shows a simple form, which contains three controls: list box, text box, And button. During initialization, the program instructs its click delegate to reference the addclick method stored elsewhere in the object. In the addclick method, the value of the text box is stored in the list box. Because the addclick method is added to the click Delegate of the button instance, this method is called every time you click the button.

public class MyForm{   ListBox listBox;   TextBox textBox;   Button button;   public MyForm()   {listBox = new ListBox(...);textBox = new TextBox(...);button = new Button(...);button.Click += new EventHandler(AddClick);}   void AddClick(object sender, EventArgs e)   {      listBox.Items.Add(textBox.Text);   }}

Use the anonymous method

The previous example is very intuitive. A separate function is created and commissioned for reference. The program calls this function whenever this delegate is called. In this function, a series of executable steps are performed. Using the anonymous method, the program can directly reference the executable steps contained in the delegate without creating the entire New Method for this class. The declaration method of the anonymous method is to first instantiate a delegate, then add a pair of curly braces indicating the execution range after the instantiation statement, and finally add a semicolon for the termination statement.

In the following example, the program modifies the delegate creation statement to directly modify the list box, instead of referencing the function representing the program to modify the list box. The purpose of the stored code is to modify the list box in the execution range after the statement is created by the delegate.

public class MyForm{   ListBox listBox;   TextBox textBox;   Button button;   public MyForm()   {listBox = new ListBox(...);textBox = new TextBox(...);button = new Button(...);button.Click += new EventHandler(sender, e){         listBox.Items.Add(textBox.Text);};}}

Note that the code in the "anonymous" method accesses and processes variables declared outside its execution scope. In fact, anonymous methods can reference variables declared by classes and parameters, or local variables declared by methods.

Passing parameters to an anonymous method

Interestingly, the "anonymous" method statement contains two parameters: sender and E. View the definition of the click Delegate of the button class. You will find that any function referenced by the delegate must contain two parameters. The first parameter is of the object type, and the second parameter is of the eventargs type. In the first example, the program does not use the "anonymous" method. Instead, it passes two parameters to the addclick method, namely the object and eventargs.

Even if you write this code in the inline mode, the delegate must still receive two parameters. In the "anonymous" method, you must declare the names of two parameters so that the associated code blocks can use them. When the click event on the trigger button is called, the "anonymous" method is called and the corresponding parameters are passed to the method.

How anonymous methods work

When an "anonymous" delegate is encountered, the C # compiler automatically converts the code within the execution range to the unique name function in the unique naming class. Then, the delegate of the stored code block is set to reference the objects and methods generated by the compiler. When a delegate is called, the "anonymous" method block is executed through the method generated by the compiler.

Back to Top

Local type

Although maintaining all source code of the type in a single file is a good method for Object-Oriented Programming, sometimes performance constraints make the type larger. In addition, in some cases, splitting a type into sub-types is unacceptable. In addition, programmers often create or use applications to publish source code and modify the result code. Unfortunately, when the source code is released again, all existing source code modifications will be overwritten.

Local types allow you to split a large number of source code types into multiple different source files for development and maintenance. In addition, local types can be used to separate the computer-generated type part from the type part written by the user, making it easier to supplement or modify the code generated by the tool.

In the following example, both the C # code files file1.cs and file2.cs define a class named Foo. If the local type is not used, a compilation error occurs because these two classes exist in the same namespace. Use the partial keyword to indicate that the compiler may include other definitions of this class elsewhere.

File1.cs file2.cs public partial class Foo {public void myfunction () {// perform the operation here} public partial class Foo {public void mytherfunction () {// perform the operation here }}

During compilation, the C # compiler will collect all definitions of local types and combine them together. The result il generated by the compiler displays a single combined class instead of multiple classes as separate classes for continuous display.

Back to Top

Compliant with standards

In December 2001, The European Computer Manufacturers Association (ECMA) approved the C # programming language as a standard (ECMA 334 ). Soon afterwards, the C # standard will be quickly tracked and approved by the International Organization for Standardization (ISO. The creation of C # standards is an important milestone in the development history of new programming languages. It indicates that many implementations are expected to be written on various operating system platforms in the future. In fact, we can see from its brief history that many third-party compiler vendors and researchers have implemented it as a standard and created their own C # compiler version.

Microsoft Welcomes customers to provide feedback on adding the features mentioned above to the C # language and intends to submit these features to the ongoing language standardization process.

Back to Top


The functions described below will be implemented in future C # compiler versions. In early 2003, Visual Studio. NET's "Everett" version will include a slightly modified C # version that fully complies with ECMA standards. This version does not include the features described in this article. Microsoft intends to include these features in Visual Studio's "vs for Yukon" version, but the release date is not yet determined.

In the next few months, Microsoft will release detailed information about these features, including all specifications. Programmers and language design groups are welcome to give their own views and feedback on these functions and any other language functions of interest. You can send an email to mailto: sharp@microsoft.com to contact the C # Language designer.

Back to Top

More information

C # community Web site: http://www.csharp.net

Visual C # (TM) product Web site: http://msdn.microsoft.com/vcsharp

Related Article

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.