2023-08-17 Unity Advanced C# Knowledge Supplement 7 - C#8 Main Functions and Grammar


​ Note: Only some functions and features that will be used in Unity development are mentioned here, and the content that is not suitable for use in Unity will be ignored.

​ C# 8 corresponds to the Unity version:

  • Unity 2020.3 —— C# 8

​ However, some new content is not yet supported in this version of Unity, and some more practical content is screened below.

​ C# 8 new features and syntax:

  1. Using statement
  2. static local function
  3. Null coalescing assignment
  4. Deconstruct function Deconstruct
  5. Pattern Matching Enhancements

1. Using statement

The Using statement is a shorthand for the using syntax. When the function is executed, the Dispose method of the object will be called to release the object.

public class Lesson10 : MonoBehaviour
{
    
    
    void Start() {
    
    
        using StreamWriter s2 = new StreamWriter("文件路径");
        
        // 对该对象进行逻辑操作
        s2.Write(5);
        s2.Flush();
        s2.Close();
        
        // 利用这个写法 就会在上层语句块执行结束时释放该对象
    }
}

Note: When using the using syntax, the declared object must inherit the System.IDisposable interface:

public class TestUsing : IDisposable
{
    
    
    public void Dispose() {
    
     }
}

public class Lesson10 : MonoBehaviour
{
    
    
    void Start() {
    
    
        using TestUsing t = new TestUsing();
    }
}

​ Because the Dispose method must be available, an error will be reported when declaring an object that does not inherit this interface.

2. Static local functions

​ A static local function is to add the static keyword in front of the local function.

​ Role: Make local functions unable to use and access any variables in the closed scope (that is, in the upper-level method), so that local functions can only process logic, and avoid making it process logic by directly changing upper-level variables to cause logic confusion.

public int TestTst(int i) {
    
    
    bool b = false;
    i += 10;
    
    Calc(ref i, ref b); // 执行静态本地函数
    
    return i;

    // 静态本地函数
    static void Calc(ref int i, ref bool b) {
    
    
        i += 10;
        b =  true;
    }
}

3. Null merge assignment

Null coalescing assignment is a newly added operator in C# 8.0 ??=, similar to the composite operator:
When左边值 ??= 右边值
the left side is empty, the value on the right side is assigned to the variable.
​ Example:

string str  = null;
str ??= "4565";
print(str); // "4565"

// 注意:由于左侧为空才会讲右侧赋值给变量,所以不为空的变量不会改变
str ??= "1111";
print(str); // "4565"

Fourth, the deconstructing function Deconstruct

​ We can declare the deconstruction function in the custom class, so that we can use the tuple writing method to obtain the variable of the custom class object.
​ Syntax: Declare a function inside a class:

​​Featurespublic void Deconstruct(out 变量类型 变量名, out 变量类型 变量名.....)
: There can be multiple Deconstructs in a class, but the number of parameters cannot be the same.

public class Person
{
    
    
    public string name;
    public bool   sex;
    public string number;
    public string email;

    // 三个解构函数
    public void Deconstruct(out string n, out bool sex) {
    
    
        n   = name;
        sex = this.sex;
    }

    public void Deconstruct(out string n, out bool sex, out string number) {
    
    
        n      = name;
        sex    = this.sex;
        number = this.number;
    }

    public void Deconstruct(out string n, out bool sex, out string number, out string email) {
    
    
        n      = name;
        sex    = this.sex;
        number = this.number;
        email  = this.email;
    }
}

public class Lesson10 : MonoBehaviour
{
    
    
    void Start() {
    
    
        // 初始化并赋值
        Person p = new Person();
        p.name   = "xxx";
        p.sex    = false;
        p.number = "123123123123";
        p.email  = "[email protected]";

        // 对该对象利用元组将其具体的变量值解构出来
        // 相当于把不同的成员变量拆分到不同的临时变量中
        (string name, bool sex) = p;
        print(name); // "xxx"
        print(sex);  // "false"
        
        string str3;
        (_, _, str3) = p;
        print(str3); // "123123123123"
    }
}

The destructor function can also be abbreviated as:

public void Deconstruct(out string n, out bool sex) => (n, sex) = (this.name, this.sex);

public void Deconstruct(out string n, out bool sex, out string number) => (n, sex, number) = (this.name, this.sex, this.number);

public void Deconstruct(out string n, out bool sex, out string number, out string email) => (n, sex, number, email) = (this.name, this.sex, this.number, this.email);

5. Pattern matching enhancements

​ In C# 7, there are already three types of pattern matching: constant pattern, type pattern and var pattern. In C# 8, the following patterns are newly added:

  • switch expression
  • attribute mode
  • tuple pattern
  • location mode

(1) switch expression

​ For the following enumerations:

public enum PosType
{
    
    
    Top_Left,
    Top_Right,
    Bottom_Left,
    Bottom_Right,
}

​ When you need to write a function to get the corresponding position, use switch to write as follows:

public Vector2 GetPos(PosType type) {
    
    
    switch (type) {
    
    
        case PosType.Top_Left:
            return new Vector2(0, 0);
        case PosType.Top_Right:
            return new Vector2(1, 0);
        case PosType.Bottom_Left:
            return new Vector2(0, 1);
        case PosType.Bottom_Right:
            return new Vector2(1, 1);
        default:
            return new Vector2(0, 0);
    }
}

A switch expression is an abbreviation for a switch statement that returns a value:

  • Use =>expression symbols instead of case:combinations
  • Use _the discard symbol insteaddefault:

​ Its usage restrictions are mainly used when there is only one line of code in the switch statement for the return value:

public Vector2 GetPos(PosType type) => type switch {
    
    
    PosType.Top_Left     => new Vector2(0, 0),
    PosType.Top_Right    => new Vector2(1, 0),
    PosType.Bottom_Left  => new Vector2(0, 1),
    PosType.Bottom_Right => new Vector2(1, 1),
    _                    => new Vector2(0, 0)
};

(2) Attribute mode

​ That is, judge each attribute on the object on the basis of the constant mode.
​ Usage: 变量 is {属性:值, 属性:值}.

​ For the following discount categories:

public class DiscountInfo
{
    
    
    public string discount;
    public bool   isDiscount;

    public DiscountInfo(string discount, bool isDiscount) {
    
    
        this.discount   = discount;
        this.isDiscount = isDiscount;
    }

    public void Deconstruct(out string dis, out bool isDis) {
    
    
        dis   = this.discount;
        isDis = this.isDiscount;
    }
}

​ If you need to judge its specific information, you need to obtain the values ​​of its two member variables for judgment:

DiscountInfo info = new DiscountInfo("5折", true);

if( info.discount == "6折" && info.isDiscount)
    print("信息相同");

​ Use the attribute mode to quickly judge:

if (info is {
    
     discount: "6折", isDiscount: true })
    print("信息相同");

Combined with switch expression:

public float GetMoney(DiscountInfo info, float money) => info switch {
    
    
    // 属性模式结合 switch 表达式判断 n 个条件是否满足
    {
    
     discount: "5折", isDiscount: true } => money * .5f,
    {
    
     discount: "6折", isDiscount: true } => money * .6f,
    {
    
     discount: "7折", isDiscount: true } => money * .7f,
    _                                    => money
};

(3) Tuple mode

​ The tuple mode does not need to declare the data structure class, and can directly use the tuple to judge:

int  ii = 10;
bool bb = true;

if ((ii, bb) is (11, true)) {
    
    
    print("元组的值相同");
}

public float GetMoney(string discount, bool isDiscount, float money) => (discount, isDiscount) switch {
    
    
    ("5折", true) => money * .5f,
    ("6折", true) => money * .6f,
    ("7折", true) => money * .7f,
    _            => money
};

(4) Position mode

​ If the deconstruction function is implemented in the custom class, you can directly use the corresponding class object and tuple to judge is:

if (info is ("5折", true)) {
    
    
    print("位置模式 满足条件");
}

At the same time, it can also cooperate with the when keyword for logical processing:

public float GetMoney2(DiscountInfo info, float money) => info switch {
    
    
    ("5折", true) when money > 100 => money * .5f,
    ("6折", true)                  => money * .6f,
    ("7折", true)                  => money * .7f,
    _                             => money
};

Guess you like

Origin blog.csdn.net/zheliku/article/details/132332065