New features in C # 8.0

Micro-channel public number: Fintech geeks
of software development engineers, working in financial information technology companies, through the CFA, the sharing of knowledge and technology combine computer and financial sector.

New features in C # 8.0

C # 8.0 has been launched to a long period of time, mainly because the company still using version 6.0, plus more personal things before, has not been concluded today the main content view and test Microsoft official document: https: // docs .microsoft.com / en-us / dotnet / csharp / whats-new / csharp-8

Read-only members (Readonly members)

Struct plus readonly in front, which represents a struct is immutable, it contains all the properties must be read-only. Read-only members so that more precise control, which means that the programmer can specify which member is set to read-only. Below is a sample code:

    public struct ReadonlyMembers
    {
        public double X { get; set; }
        public double Y { get; set; }
        public double Z { get; set; }
        public double Distance => Math.Sqrt(X * X + Y * Y + Z * Z);

        public readonly override string ToString() => $"({X}, {Y},{Z}) is {Distance} from the origin";

        public readonly void TestReadOnly()
        {
            //X = 10;//Complier error: Cannot assign to 'X' because it is read-only
        }
    }

The above code fragment comprises a modified readonly two functions: ToString and TestReadOnly. In TestReadOnly, if you attempt to assign X, the compiler will give an error message comments.
Further, ToString used in a compile Distance warning:. CS8656 Call to non-readonly member 'ReadonlyMembers.Distance.get' from a 'readonly' member results in an implicit copy of 'this' because the compiler does not struct think get does not change the state, it must set the Distance display is readonly, but you do not need to automatically attribute, the compiler will think that it does not get access to modify the state, so access X, Y, Z members in ToString It will not cause a compiler warning.

The default interface method (Default interface methods)

In previous versions, the interface can not contain partially achieved, so once add a new member in the interface, all the places that implements this interface will need to be modified, and this new feature allows the addition of new members can give their time to achieve, so such that where no modifications are needed to implement the interface. One thing to note is the implementation of the interface is not as inheritance and implement interfaces like class inheritance, so when implementing interface calls, to use interface type can not be used to achieve the type. Note: This feature is not supported in .Net Framewok4.8, the compiler error below, and in the .Net Core 3.0 is supported.

.Net Framework Error

Here is an example of the default interface:

    public interface ICustomer
    {
        string Name { get; set; }

        int OrderCount { get; set; }

        public string GetOrderCount();

        public string GetName()//default implemented method
        {
            return Name;
        }

        protected void PrintName()
        {
            Console.WriteLine("Name:" + Name ?? "");
        }

        private void DummyPrivateMethod()
        {
            Console.WriteLine("Name:" + Name ?? "");
        }
    }

    public class FintechCustomer : ICustomer
    {
        public string Name { get; set; }
        public int OrderCount { get; set; } = 100;

        public string GetOrderCount()
        {
            return $"FintechCustomer order count:{OrderCount}";
        }

        public string GetName()//override default implemented method
        {
            return $"FintechCustomer Name:{Name}";
        }

        public FintechCustomer(string name) => Name = name;

    }

    public class NormalCustomer : ICustomer
    {
        public string Name { get; set; }
        public int OrderCount { get; set; }

        public string GetOrderCount()
        {
            return $"Normal customer order count:{OrderCount}";
        }

        public NormalCustomer(string name)
        {
            Name = name;
            OrderCount = 0;
        }
    }

The code contains a two implementation classes and interfaces ICustomer FintechCustomer, NormalCustomer. There are several points to note:

  1. ICustomer interface provides a concrete implementation of GetName
  2. FintechCustomer GetName class provides its own implementation, thereby covering ICustomer the GetName
  3. NormalCustomer class does not provide its own GetName achieved, but there is no inheritance ICustomer the GetName, calling through the following example, we can verify this point
  4. Inside ICustomer interface, members can add various modifiers such as: private, protected, public, etc., but they will not be inherited.

Code calls the examples are as follows:

    public class DefaultInterfaceImplementationUnitTest
    {
        [TestMethod]
        public void FintechCustomer_TestGetName()
        {
            var name = "FintechCustomer1";
            var fc = new FintechCustomer(name);
            ICustomer ic = fc;
            Assert.AreEqual($"FintechCustomer Name:{name}", fc.GetName());
            Assert.AreEqual($"FintechCustomer Name:{name}", ic.GetName());
        }

        [TestMethod]
        public void NormalCustomer_TestGetName()
        {
            var name = "NormalCustomer1";
            var nc = new NormalCustomer(name);
            ICustomer ic = nc;
            //Assert.AreEqual(name, nc.GetName());//编译错误: Error CS1061  'NormalCustomer' does not contain a definition for 'GetName'...
            Assert.AreEqual(name, ic.GetName());
        }
    }

In NormalCustomer_TestGetName function, the line is commented out shows, a reference to the implementation class NormalCustomer can not call interfaces ICustomer implemented GetName function, and can only be called by GetName ICustomer references. However, FintechCustomer_TestGetName, we can see whether or reference ICustomer of FintechCustomer can call GetName function, and is a function of FintechCustomer the call.

More Pattern Matching

C # 7.0 introduces a type and is constant and by matching switch, C # 8.0 where the extended use thereof. These properties are primarily functions to support data separate programming paradigm, and when the data is separate function or algorithm does not depend on the type of runtime objects, consider using these properties, they provide an alternative design of the expression of the way. We will be mentioned below switch expression and property, tuple, postition three pattern matching.

switch expression (Switch Expression)

Look at an example

        public static RGBColor FromRainbow(Rainbow colorBand) =>
            colorBand switch
            {
                Rainbow.Red => new RGBColor(0xFF, 0x00, 0x00),
                Rainbow.Orange => new RGBColor(0xFF, 0x7F, 0x00),
                Rainbow.Yellow => new RGBColor(0xFF, 0xFF, 0x00),
                Rainbow.Green => new RGBColor(0x00, 0xFF, 0x00),
                Rainbow.Blue => new RGBColor(0x00, 0x00, 0xFF),
                Rainbow.Indigo => new RGBColor(0x4B, 0x00, 0x82),
                Rainbow.Violet => new RGBColor(0x94, 0x00, 0xD3),
                _ => throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand)),
            };

        public enum Rainbow
        {
            Red,
            Orange,
            Yellow,
            Green,
            Blue,
            Indigo,
            Violet
        }

From the example above FromRainbow, we can see that the switch expression compared to the switch statement has undergone great changes, mainly in the following four points:

  1. Variable name (colorBand) on the front of the switch keyword, so that the compiler can easily switch statement and switch expression.
  2. => Substituted and the case: one end of each use and is not; so that a more simple and intuitive.
  3. _ default branch is substituted.
  4. Piece of code is an expression rather than a statement.

Finally, switch expression must return a value or throw an exception, if a call does not match the case, an exception will be thrown InvalidOperation, the compiler will also switch branch does not include all cases when a warning is given.

Attribute pattern (Property Pattern)

The following example is a talk from

       public static decimal ComputeSalesTax(Address location, decimal salePrice) =>
            location switch
            {
                { State: "WA" } => salePrice * 0.06M,
                { State: "MN" } => salePrice * 0.75M,
                { State: "MI" } => salePrice * 0.05M,
                // other cases removed for brevity...
                _ => 0M
            };

        public class Address
        {
            public string State { get; set; }
        }

The above code uses a switch function ComputeSalesTax expressions, matching the interior of the switch expression uses the attribute pattern. The following represents an example: If the location of the State attribute value of "WA", it returns salePrice * 0.06M:

 { State: "WA" } => salePrice * 0.06M,

Tuple pattern (tuple pattern)

Some algorithms require a plurality of inputs, the model allows the tuple in the tuple switch used to match a plurality of expression values, the following is an example:

    public static string RockPaperScissors(string first, string second)
    => (first, second) switch
    {
        ("rock", "paper") => "rock is covered by paper. Paper wins.",
        ("rock", "scissors") => "rock breaks scissors. Rock wins.",
        ("paper", "rock") => "paper covers rock. Paper wins.",
        ("paper", "scissors") => "paper is cut by scissors. Scissors wins.",
        ("scissors", "rock") => "scissors is broken by rock. Rock wins.",
        ("scissors", "paper") => "scissors cuts paper. Scissors wins.",
        (_, _) => "tie"
    };

The above is the rock paper scissors game, the switch expression can be seen using a matching tuple is also only returns that message, wherein the ( , ) => "TIE" indicates no match is found, the return to "tie".

Position mode (Positional patterns)

C # 7.0 introduces Deconstruct function, if there are a class Deconstrut function, it can be directly decomposed into different properties of the class of variables. In C # 8.0 can be matched in a plurality of attributes by the position switch expression pattern, the following is an example:

        public static Quadrant GetQuadrant(Point point) => point switch
        {
            (0, 0) => Quadrant.Origin,
            var (x, y) when x > 0 && y > 0 => Quadrant.One,
            var (x, y) when x < 0 && y > 0 => Quadrant.Two,
            var (x, y) when x < 0 && y < 0 => Quadrant.Three,
            var (x, y) when x > 0 && y < 0 => Quadrant.Four,
            var (_, _) => Quadrant.OnBorder,
            _ => Quadrant.Unknown
        };

        public class Point
        {
            public int X { get; }
            public int Y { get; }

            public Point(int x, int y) => (X, Y) = (x, y);

            public void Deconstruct(out int x, out int y) =>
                (x, y) = (X, Y);
        }

In this example, Point class contains Deconstruct function, so that it can be X, Y, decomposed into a separate variable. In GetQuadrant function, the object is decomposed into point x, y by Deconstruct two variables function, and when judged by whether or not the branch condition is satisfied.

using statement

In the previous version, we can use the using statement to ensure the realization of the IDisposable objects at the end of the life cycle, its Dispose method is called. In C # 8.0, we do the same thing using statement and code more compact. Here is an example of an open file:

static int WriteLinesToFile(IEnumerable<string> lines)
{
    using var file = new System.IO.StreamWriter("WriteLines2.txt");
    // Notice how we declare skippedLines after the using statement.
    int skippedLines = 0;
    foreach (string line in lines)
    {
        if (!line.Contains("Second"))
        {
            file.WriteLine(line);
        }
        else
        {
            skippedLines++;
        }
    }
    // Notice how skippedLines is in scope here.
    return skippedLines;
    // file is disposed here
}

In the above example, when the function call returns the file object will automatically call the Dispose method, if using declared object does not implement IDisposable, the compiler generates an error message.

Static local function (Static local functions)

If you do not want to visit a local function that is captured outside its local variables, we can add static limit, the following is an example:

        public int Add(int x, int y)
        {
            return x + y;

            int GetX()
            {
                return x;
            }

            static int GetY()
            {
                return y;//Compiler error:A static local function cannot contain a reference to 'y'
            }
        }

In the above example, Add function contains two local functions, which GetY is static, but it refers to a local variable peripheral y, so there will be a comment in the compilation errors.

Disposable ref structs

Because the structure of the ref does not implement any interfaces, of course IDisposable does not work, so it can not be dispose of. In C # 8.0, so long as it has an accessible void Dispose () function, it can be the Dispose, examples are as follows:

    ref struct DisposableRefStruct
    {
        public void Dispose()
        {
            Console.WriteLine("ref struct dispose method is called");
        }
    }

    public class DisposableRefStructTester
    {
        public static void Test()
        {
            using (var s = new DisposableRefStruct())
            {
                Console.WriteLine("Test Disposable Ref Struct");
            }
        }

As can be seen from the example DisposableRefStruct not implement IDisposable interface, but void Dispose () method, it is also possible using statement with the word. This feature is also available readonly ref struct

May be null reference type (Nullable reference types)

Can be turned on by adding the following configuration in the project file can be null reference type checking. After opening, the compiler will think that all reference types are not assigned a null value, must be as null type the same as before, after the type plus? To represent the reference types can be empty. For details, refer:
https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references
https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/nullable-reference- types
https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/upgrade-to-nullable-references

<Nullable>enable</Nullable>

Asynchronous flow (Asynchronous streams)

The function corresponding to the synchronization IEnumerable Asynchronous version, the asynchronous stream function has the following three features:

  1. Use async modified
  2. Return type is: IAsyncEnumerable
  3. Function contains statements to implement yield return enumerator paradigm
    Here is an example:
        public static async IAsyncEnumerable<int> GenerateSequence()
        {
            for (int i = 0; i < 20; i++)
            {
                await Task.Delay(100);
                yield return i;
            }
        }

        public static async Task ConsumeAsyncStream()
        {
            await foreach (var i in GenerateSequence())
            {
                Console.WriteLine(i);
            }
        }

Returns the embodiment GenerateSequence ConsumeAsyncStream an asynchronous stream to enumerate the asynchronous stream by adding a front await foreach.

Index and range (Indices and ranges)

And the range of indices to access a single element or a range of sequence provides simple syntax. This concept a bit like a slice of Python, but the syntax is slightly different. This function is implemented depends on the following two new types and two new operators:

  1. System.Index, denotes a sequence index
  2. ^ Operator denotes the index is started from the back
  3. System.Range, represents a sub-sequence of
  4. ... operator indicates the beginning and end of a range of

    Some code examples are as follows:

public class IndicesAndRanges
    {
        public string[] words = new string[]
                               {
                                            // index from start      index from end
                                "The",      // 0                     ^9
                                "quick",    // 1                     ^8
                                "brown",    // 2                     ^7
                                "fox",      // 3                     ^6
                                "jumped",   // 4                     ^5
                                "over",     // 5                     ^4
                                "the",      // 6                     ^3
                                "lazy",     // 7                     ^2
                                "dog"       // 8                     ^1
                               };           // 9 (or words.Length)   ^0

        public void Test()
        {
            Console.WriteLine($"The last word is {words[^1]}"); // writes "dog"
            var quickBrownFox = words[1..4];// "quick", "brown", and "fox"
            var lazyDog = words[^2..^0];//"lazy" and "dog"

            var allWords = words[..]; // contains "The" through "dog".
            var firstPhrase = words[..4]; // contains "The" through "fox"
            var lastPhrase = words[6..]; // contains "the", "lazy" and "dog"


            Range phrase = 1..4;//Range phrase = 1..4;
            var text = words[phrase];
        }
    }

Null merger assignment

C # 8.0 introduces a null = ?? combined assignment operator. Only when the left operand is null, its value to the right operand assigned to the left operand. Examples are as follows:

List<int> numbers = null;
int? i = null;

numbers ??= new List<int>();
numbers.Add(i ??= 17);
numbers.Add(i ??= 20);

Console.WriteLine(string.Join(" ", numbers));  // output: 17 17
Console.WriteLine(i);  // output: 17

Unmanaged constructed type

Previously, the configuration of the type (type comprising at least one type of parameters) can not be unmanaged type. Starting from the C # 8.0, if the value of the type of structure comprising only unmanaged type field, the type is not managed, the following examples:

public struct Coords<T>
{
    public T X;
    public T Y;
}

It is unmanaged and other types, can be created or a pointer to the allocated memory block on the type stack.

Nested expression stackalloc

C # 8.0, if the result of the expression is the type stackalloc System.Span Or System.ReadOnlySpan , Can be used in the expression stackalloc other expressions, the following is a specific example:

Span<int> numbers = stackalloc[] { 1, 2, 3, 4, 5, 6 };
var ind = numbers.IndexOfAny(stackalloc[] { 2, 4, 6 ,8 });
Console.WriteLine(ind);  // output: 1

String interpolation enhancement

String interpolation in the order of $ and @ marks can be positioned anywhere: $ @ "..." and $ @ "..." is correct, but in earlier versions of C #, $ mark must appear before the @ sign .


Fintech Geeks

Guess you like

Origin www.cnblogs.com/dereklovecc/p/12393155.html
Recommended