New features of C # 7.0 language

Source: Internet
Author: User
Tags microsoft c
The following is a description of the scheduling feature in the c#7.0 language. Most of these features can be run in Visual Studio "4" in preview. Now is the best trial period, please record your thoughts.

The c#7.0 language adds a number of new features that drive focus on data consumption, simplifying code and performance.

Perhaps the biggest feature is the tuple (tuples), which makes it easy to have multiple results, and thus simplifies the code to match patterns that are conditional on the shape of the data. But there are many other features that want to combine them to make the code run more efficiently, more clearly, and get more creative. If you have a feature that is not what you want or you want to improve, use the "Send Feedback" feature at the top of the Visual Studio window to feed the results back to us. In the many features I described in preview 4 there is no way to fully run, according to the user feedback results, we will be in the release of the final version is to add some new features. It is important to note that some of the features in the existing plan may be changed or canceled in the final version.

If you are interested in this feature setting and want to learn it, you can find a lot of design notes and discussions on Roslyn GitHub site.

Output (out) variable

Currently in C #, the use of out parameters is not as smooth as we thought. When calling a method with an out parameter, you must first declare the variable passed to it. Although you typically do not initialize these variables (they will all be overwritten after this method), you cannot declare them using VAR, but you need to specify the full type:

public void Printcoordinates (point p) {    int x, y;//has to ' Predeclare '    p.getcoordinates (out x, out y);    WriteLine ($ "({x}, {y})");

In c#7.0, we add an out variable that declares a variable right as the point passed by the out parameter:

public void Printcoordinates (point p) {    p.getcoordinates (out int x, out int y);    WriteLine ($ "({x}, {y})");

It is important to note that the variables are within the enclosing block scope, so they can be used later. Most types of statements do not establish their own scope of application, so out variables are usually introduced into the enclosing scope in the declaration.

Note : In preview 4, the applicable scope rules are stricter: the scope of the out variable is their claim in the declaration. Therefore, the above example is not used in subsequent versions.

Because the out variable is directly declared as a parameter passed to the out parameter, the compiler can usually tell the type (unless there is a conflicting overload). So it is very useful to declare them with Var rather than a type:

P.getcoordinates (out Var ×, out Var y);

A common use of out parameters is try ... The pattern, where the out parameter is a Boolean return indicating success, the out parameter results in the resulting:

public void Printstars (string s) {    if (int. TryParse (s, out var i)) {WriteLine (New string (' * ', i));}    else {WriteLine ("Cloudy-no stars tonight!");}}

Note : The good thing about Preview 4 is that it is simply defined with an if statement.

The plan allows "wildcards" as an out parameter and in the form of *, ignoring unimportant out parameters:

P.getcoordinates (out int ×, out *); I only care about X

Note:It is still unknown whether wildcards can turn it into a c#7.0.

Pattern matching

C # 7.0 introduces the concept of a pattern , which, in abstract terms, is a syntactic component that can be used to test whether a value has a certain "shape" and additional information obtained from the value as it works.

Here is an example of a pattern in C # 7.0:

    • C is a constant pattern (c is a constant expression in C #) that is used to test whether the input parameter is equal to C

    • The type mode of T X (T is a type, x is an identifier) and is used to test whether the input parameter has a type T, and if so, extracts the value of the input parameter into a new x variable of type T.

    • The var x variable pattern (x is an identifier), usually matches and simply places the value of the input parameter into a new variable X

This is a start, the pattern is a new C # language element, and we can add them to C # in the future.

In C # 7.0, we are working with patterns to enhance two existing language constructs:

    • The IS expression now can have a pattern on the right, not just a type

    • Case clauses can now be matched by patterns in a switch statement, not just constant values

In the future of C #, we may add more places to use patterns.

An IS expression with a pattern

This is an example of an IS expression that uses a constant pattern and a type pattern:

public void Printstars (object o) {    if (O is null) return;     Constant pattern "null"    if (! ( o is int i)) return; Type pattern "int i"    WriteLine (New string (' * ', i));}

As you can see, the pattern variables (variables are introduced through the pattern) are somewhat similar to the out variables described earlier, they are declared in the expression and can be used within their nearest perimeter. Also like out variables, pattern variables are variable,

Note : Just like out variables, strict scope rules apply to Preview 4.

Patterns and Try methods typically appear together:

if (o is int i | | (O is string s && int. TryParse (s, out i)) {/* use I/*}

Switch statements with a pattern

We are generalizing the switch statement, so:

    • You can use switch on any type (not just the original type)

    • Patterns can be used in case clauses

    • The case clause can have additional conditions

Here is a simple example:

Switch (SHAPE) {case    Circle C:        WriteLine ($ ' circle with radius {C.radius} ");        break;    Case Rectangle s when (s.length = = s.height):        WriteLine ($ "{s.length} x {s.height} square");        break;    Case Rectangle R:        WriteLine ($ "{r.length} x {r.height} Rectangle");        break;    Default:        WriteLine ("<unknown shape>");        break;    Case NULL:        throw new ArgumentNullException (nameof (Shape));}

There are a few things to note about this new extension of the switch statement:

    • The order of the case clauses is now important: like a catch clause, the case clause is no longer necessarily disjoint, and the first clause matches the selection. So the important thing here is that the square case in the above code is earlier than the rectangle case. As well as the catch clause, the compiler will help you by marking the obvious unreachable situation. Before that, you never know the order of evaluations, so this is not a major change in nature.

    • The default clause is always the last to be evaluated: even if the null clause in the preceding code is the last, it will be checked before the default clause is selected. This is intended to be compatible with existing switch semantics. However, a good practice usually lets you put the default clause at the end.

    • The null clause is not reachable at last: this is because the type pattern follows the example of the current is expression and does not match the null value. This ensures that the null value is not accidentally picked up by any of the type patterns. You have to be more specific about how to handle them (or leave them for the default clauses).

By case ...: The pattern variable introduced by the tag only exists in the range of the corresponding switch part.


It is common practice to want to return multiple values from one method. The currently available options are not optimal:

    • Out parameter. Using clumsiness (even if there is an elevation described above), they do not run using asynchronous methods.

    • System.tuple<...> the return type. Use a encumbrance and require the allocation of a tuple object.

    • Customize the transport type for each method: a large amount of code for the purpose of type overhead is to temporarily collect some values

    • An anonymous type returns a type by returning a dynamic. High performance overhead and no static type checking.

To do better in this respect, C # adds a tuple types and a tuple literals:

(String, String, String) Lookupname (Long ID)//tuple return type{...    //Retrieve first, middle and last from data storage    return (first, Middle, last); Tuple literal}

This method currently effectively returns three strings, which are wrapped as elements in a tuple type.

The caller of the method will accept a tuple and can access the element one at a.

var names = Lookupname (ID); WriteLine ($ "found {names. ITEM1} {names. ITEM3}. ");

ITEM1, etc., is the default name of the tuple element and can be used frequently. But they are not too well described, so you can selectively add a better one.

(string First, string middle, string last) Lookupname (Long ID)//tuple elements has names

Now the tuple's recipient has more descriptive names to run:

var names = Lookupname (ID); WriteLine ($ "found {Names.first} {names.last}.");

You can also specify the name directly in the tuple literals:

Return (First:first, Middle:middle, last:last); Named tuple elements in a literal

Typically, you can assign a tuple-type-independent name to each other, as long as the individual elements can be assigned, and the tuple type is freely converted to other tuple types. In particular, for tuple literals, there are some limitations, which warn or prompt in the case of common errors, such as accidental interchange of element names.

Note: These restrictions are not yet implemented in Preview 4

Tuples are value types, and their elements are only public, variable fields. Their values are equal, representing that the two tuples are equal (both have the same Haas code) if their elements are pair matched (both have the same Haas code).

This makes tuples useful for many situations under multiple return values. For example, if you need a dictionary with multiple keys, use tuples as your keys, and everything will work as usual. If you need to have a list with multiple values in each location, use tuples, find lists, and so on, the program will work.

Note: Tuples rely on a series of underlying types that are not introduced in Preview 4. For future work, you can easily get them by NuGget: Right-click on the project in the solution Explorer and select "Manage NuGet Packages ..." Select the "Browse" tab, check "Include prerelease" and select "" as "package source" to search for "system.valuetuple" and install it


Another way to eliminate tuple (tuple) is to deconstruct the tuple. A tuple (or other value) is split into several parts and redefined as a new variable through a deconstructed declaration syntax.

(string First, string middle, string last) = Lookupname (ID1); Deconstructing declarationwriteline ($ "found {first} {last}.");

The var keyword can be used in deconstruction:

(var first, var middle, var last) = Lookupname (ID1); var inside

or extract the var keyword outside the brackets:

var (first, middle, last) = Lookupname (ID1); var outside

You can also deconstruct an existing variable by refactoring the assignment:

(First, middle, last) = Lookupname (ID2); Deconstructing Assignment

Not only can the tuple be deconstructed, any type can be deconstructed, as long as there is a corresponding (entity or extension) Deconstruction method:

public void deconstruct (out T1 x1, ..., out Tn xn) {...}

The output parameters are composed of the resulting values after the deconstruction.

(Why use data parameters instead of returning a tuple?) In this way, you can reload several different values)

Class point{public    int X {get;}    public int Y {get;}    public point (int x, int y) {x = x; y = y; } public    void deconstruct (out int x, out int y) {x = x; y = y;}} (Var myx, var MyY) = GetPoint (); Calls deconstruct (out Myx, out MyY);

This will become a common pattern that includes destructors and "symmetric" parsing:

For output variables, we plan to allow the use of "wildcard characters" in deconstruction:

(Var myx, *) = GetPoint (); I only care about MYX
Note: It is still not determined whether to introduce wildcards into C # 7.0.

Local functions

Sometimes, an auxiliary function is meaningful only within a single method that uses it. Now you can declare these functions as a local function within other functional bodies:

public int Fibonacci (int x) {    if (x < 0) Throw the new ArgumentException ("Less negativity please!", nameof (x));    return Fib (x). Current;    (int current, int previous) Fib (int i)    {        if (i = = 0) return (1, 0);        var (p, pp) = Fib (i-1);        return (P + pp, p);}    }

Parameters and closed interval local variables can be used within local functions, like lambda expressions.

For example, a method implementation iterator typically requires a strict check of the call-time non-iterator encapsulation method. (The iterator itself is not running, only the call to MoveNext will run). The local function is perfect in this case:

Public ienumerable<t> filter<t> (ienumerable<t> source, func<t, bool> Filter) {    if (Source = = null) throw new ArgumentNullException (nameof (source));    if (filter = = null) throw new ArgumentNullException (nameof (filter));    return Iterator ();    Ienumerable<t> Iterator ()    {        foreach (var element in source)         {            if (filter (element)) {yield return Element }        }    }}

If the iterator is the next filter for a private method, it may be accidentally used by other members (no parameter checking). Also, as a filter, it will need to take all the same parameters instead of specifying the parameters within the domain.

Note: in preview 4, local functions must be declared before they are called. This restriction will be relaxed and can invoke local variables that read directly assigned values.

Literal improvements

C # 7.0 allows the use of "_" as a numeric delimiter in the digital literals :

var d = 123_456;var x = 0xab_cd_ef;

You can put it in the position you want to improve readability. This has no effect on the value.

In addition, C # 7.0 also introduces the binary literals, so you can specify binary mode directly without having to know the hexadecimal symbol.

var B = 0b1010_1011_1100_1101_1110_1111;

REF returns and local

Just as you can pass things through reference (with the ref modifier) in C #, you can now return them through reference and store them in local variables through reference.

Public ref int Find (int number, int[] numbers) {for    (int i = 0; i < numbers. Length; i++)    {        if (numbers[i] = = number)         {            return ref numbers[i];//return the storage location, not the Value
  }    }    throw new IndexOutOfRangeException ($ "{nameof (number)} not found");} Int[] Array = {1, -39, 0, 7, +, -12};ref int place = ref Find (7, array); Aliases 7 ' s place in the Arrayplace = 9; Replaces 7 with 9 in the Arraywriteline (Array[4]); Prints 9

This is useful for bypassing placeholders as large data structures. For example, a game might hold its data in a large pre-allocated array structure (to avoid garbage collection pauses). Methods can directly return a reference to such a structure, and it can be read and modified by the caller.

Here are some restrictions to make sure that this is safe:

    • You can only return refs to those that are "safe to return": those that are passed to you, and those that point to the object's fields.

    • Ref locals is initialized to a storage location and cannot be mutated to point to another.

Generalized asynchronous return types

So far, calling async methods in C # must return Void,task or task<t>. c#7.0 allows you to define other types in such a way that they can be returned from an async method.

For example, we plan to have a valuetask<t> struct type. It is built on the prevention of the allocation of Task<t> objects when the result of an asynchronous operation is already in the case of waiting time. For many asynchronous scenarios, such as taking a buffer as an example, this can significantly reduce the number of allocations and make a significant performance improvement.

There are a number of other ways you can imagine that a custom "task-like" type is useful. It won't be simple to create correctly, so we don't expect most people to launch their own, but they're likely to start showing up in frameworks and APIs, and then callers can go back and await the way they do tasks today.

Note: The generalized asynchronous return type has not been applied in preview 4.

More expression-bodied methods

Expression-bodied methods, properties, and so on are all major breakthroughs in C # 6.0, but they are not allowed to be used in a variety of member, c#7.0 add accessors, constructors, finalizers, etc. Enable more member to use the Expression-bodied method:

Class person{    private static concurrentdictionary<int, string> names = new Concurrentdictionary<int, String> ();    private int id = GetId ();    Public person (string name) = names. TryAdd (ID, name); Constructors    ~person () = names. Tryremove (ID, out *);              Destructors public    string Name    {        get = Names[id];                                 Getters        set = Names[id] = value;                         Setters    }}
Note: These additional expression-bodied methods have not yet worked in preview 4.

This is a community-contributed feature, not a Microsoft C # team. and, open source!

It's easy to throw an exception in the middle of an expression, just call a method for yourself, but in c#7.0 we allow the expression to be thrown directly in some places:

Class person{Public    string Name {get;}    Public person (string name) = = Name = Name?? throw new ArgumentNullException (name);    public string Getfirstname ()    {        var parts = name.split ("");        Return (parts. Length > 0)? Parts[0]: Throw new InvalidOperationException ("No name!");    }    public string getlastname () = throw new NotImplementedException ();
Note: The throw expression has not yet worked in preview 4.

This address:

Original address:

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: 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.