2023-08-15 Untiy进阶 C#知识补充6——C#7主要功能与语法


​ 注意:在此仅提及 Unity 开发中会用到的一些功能和特性,对于不适合在 Unity 中使用的内容会忽略。

​ C# 7 对应 Unity 版本:

  • Unity 2018.3 支持 C# 7
  • Unity 2019.4支持 C# 7.3

​ 7.1、7.2、7.3 相关内容都是基于 C# 7 的一些改进

​ C# 7 新增功能和语法:

  1. 字面值改进
  2. out 内部声明 / 弃元
  3. ref 返回值
  4. 本地函数
  5. 抛出表达式
  6. 元组
  7. 模式匹配
一、字面值改进

​ 在声明数值变量时,为了方便查看数值,可以在数值之间插入 “_” 作为分隔符。

​ 主要作用:方便数值变量的阅读。

int i = 9_9123_1239;
print(i);  // "991231239"

int i2 = 0xAB_CD_17;
print(i2); // "11259159"
二、out 内部声明 / 弃元

​ 不需要再使用带有 out 参数的函数之前,声明对应变量。
​ 作用:简化代码,提高开发效率。

​ 举例:

public class Lesson8 : MonoBehaviour
{
    public void Calc(out int a, out int b) {
        a = 10;
        b = 20;
    }

    public void Calc(out float a, out float b) {
        a = 10;
        b = 20;
    }
}

(一)以往 out 使用方式

public class Lesson8 : MonoBehaviour
{
    void Start() {
        int a;
        int b;
        Calc(out a, out b);
    }
}

(二)现在的用法

public class Lesson8 : MonoBehaviour
{
    void Start() {
        Calc(out int a, out int b);
        
        print(x); // "10"
        print(y); // "20"
    }
}

​ 可以配合 var 类型使用,但是在函数重载时需要指明哪种类型:

Calc(out var a, out var b); // 报错,不清楚 a、b 是 int 还是 float
Calc(out int a, out var b); // 通过,b 识别为 int

(三)使用弃元符号 “_”

​ 使用 “_” 弃元符号,省略不想使用的参数:

public class Lesson8 : MonoBehaviour
{
    void Start() {
        Calc(out int c, out _); // 参数 b 不使用
        print(c);
    }
}
三、ref 返回值

​ 使用 ref 修饰临时变量和函数返回值,可以让赋值变为引用传递,即 C++ 中的 & 引用类型。
​ 作用:用于修改数据对象中的某些值类型变量。

(一)引用变量

public struct TestRef
{
    public int atk;
    public int def;

    public TestRef(int atk, int def) {
        this.atk = atk;
        this.def = def;
    }
}

public class Lesson8 : MonoBehaviour
{
    void Start() {
        int     testI  = 100;
        ref int testI2 = ref testI; // testI2 与 testI 指向同一块数据内存
        testI2 = 900;
        print(testI);               // "900"

        TestRef     r  = new TestRef(5, 5);
        ref TestRef r2 = ref r;     // r2 与 r 指向同一个类
        r2.atk = 10;
        print(r.atk);               // "10"
    }
}

(二)函数返回值

public class Lesson8 : MonoBehaviour
{
    // 寻找数组中是否存在 number 成员,并返回其引用
    // 若找不到,则返回第一个成员的引用
    public ref int FindNumber(int[] numbers, int number) {
        for (int i = 0; i < numbers.Length; i++) {
            if (numbers[i] == number)
                return ref numbers[i];
        }
        return ref numbers[0];
    }
    
    void Start() {
        int[]   numbers = new int[] { 1, 2, 3, 45, 5, 65, 4532, 12 };
        ref int number  = ref FindNumber(numbers, 5); // 获取数组中第 5 个成员的引用
        number = 98765;
        print(numbers[4]); // "98765"
    }
}
四、本地函数

​ 在函数内部可以声明一个临时函数。
​ 注意:

  • 本地函数只能在声明该函数的函数内部使用
  • 本地函数可以使用声明自己的函数中的变量

​ 作用:方便逻辑的封装
​ 建议:把本地函数写在主要逻辑的后面,方便代码的查看

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

    // 本地函数
    void Calc() {
        i += 10;
        b =  true;
    }
}
五、抛出表达式

​ 抛出表达式,就是指抛出一个错误。一般的使用方式为:throw 后面 new 一个异常类

​ 异常基类:Exception

表1 C#自带异常类
异常类说明
IndexOutOfRangeException当一个数组的下标超出范围时运行时引发
NullReferenceException当一个空对象被引用时运行时引发
ArgumentException方法的参数是非法的
ArgumentNullException一个空参数传递给方法,该方法不能接受该参数
ArgumentOutOfRangeException参数值超出范围
SystemException其他用户可处理的异常的基本类
OutOfMemoryException内存空间不够
StackOverflowException堆栈溢出
ArithmeticException出现算术上溢或者下溢
ArrayTypeMismatchException试图在数组中存储错误类型的对象
BadImageFormatException图形的格式错误
DivideByZeroException除零异常
DllNotFoundException找不到引用的 DLL
FormatException参数格式错误
InvalidCastException使用无效的类
InvalidOperationException方法的调用时间错误
MethodAccessException试图访问思友或者受保护的方法
MissingMemberException访问一个无效版本的 DLL
NotFiniteNumberException对象不是一个有效的成员
NotSupportedException调用的方法在类中没有实现
InvalidOperationException当对方法的调用对对象的当前状态无效时,由某些方法引发

​ 在 C# 7 中,可以在更多的表达式中进行错误抛出。
​ 好处:更节约代码量。

(一)空合并操作符后用 throw

private void InitInfo(string str) => jsonStr = str ?? throw new ArgumentNullException(nameof(str));

(二)三目运算符后面用 throw

private string GetInfo(string str, int index) {
    string[] strs = str.Split(',');
    return strs.Length > index ? strs[index] : throw new IndexOutOfRangeException();
}

(三)=> 符号后面直接 throw

Action action = () => throw new Exception("错了,不准用这个委托");
六、元组

​ 多个值的集合,相当于是一种快速构建数据结构类的方式。

​ 在函数存在多返回值时可以使用元组 (返回值 1 类型, 返回值 2 类型, ....) 来声明返回值;

​ 在函数内部返回具体内容时通过 (返回值 1, 返回值 2, ....) 进行返回。
​ 主要作用:提升开发效率,更方便的处理多返回值等需要用到多个值时的需求。

(一)无变量名元组

(int, float, bool, string) yz = (1, 5.5f, true, "123");

print(yz.Item1); // "1"
print(yz.Item2); // "5.5" 
print(yz.Item3); // "true"
print(yz.Item4); // "123"

(二)有变量名元组

(int i, float f, bool b, string str) yz2 = (1, 5.5f, true, "123");

print(yz2.i);   // "1"
print(yz2.f);   // "5.5" 
print(yz2.b);   // "true"
print(yz2.str); // "123"

(三)元组的比较

​ 元组可以进行等于和不等于的判断:

  • 数量相同才比较;
  • 类型相同才比较;
  • 每一个参数的比较通过 == 比较,都是 true 才认为两个元组相等。
print(yz == yz2); // "true"

(四)成员变量

​ 元组不仅可以作为临时变量,成员变量也是可以的:

public class Lesson9 : MonoBehaviour
{
    public (int, float) yz;
    
    void Start() {
        print(this.yz.Item1); // "0",未初始化,int 默认值为 0
    }
}

(五)元组解构

​ 把多返回值元组拆分到不同的变量中:

public class Lesson9 : MonoBehaviour
{
    private (string str, int i, float f) GetInfo() {
        return ("123", 2, 5.5f);
    }
    
    void Start() {
        int    myInt;
        string myStr;
        float  myFloat;
        
        (myStr, myInt, myFloat) = GetInfo(); // 解构
        
        print(myStr);   // "123"
        print(myInt);   // "2"
        print(myFloat); // "5.5"
    }
}

​ 可以简化写成:

(string myStr, int myInt, float myFloat) = GetInfo();

​ 亦可以使用弃元:

(string ss, _, _) = GetInfo(); // 不使用参数 i 和 f
print(ss);

​ 字典中键的应用:

Dictionary<(int i, float f), string> dic = new Dictionary<(int i, float f), string>();
dic.Add((1, 2.5f), "123");

if (dic.ContainsKey((1, 2.5f))) {
    print("存在相同的键");
    print(dic[(1, 2.5f)]);
}
七、模式匹配

​ 模式匹配是一种语法元素,可以测试一个值是否满足某种条件,并可以从值中提取信息。

​ 在 C# 7 中,模式匹配增强了两个现有的语言结构:

  1. is 表达式:可以在右侧写一个模式语法,而不仅仅是一个类型
  2. switch 语句中的 case

​ 主要作用:节约代码量,提高编程效率

(一)常量模式

(is 常量)

​ 用于判断输入值是否等于某个值。

object o = 1.5f;

if (o is 1) {
    print("o是1");
}

if (o is null) {
    print("o是null");
}

(二)类型模式

(is 类型 变量名、case 类型 变量名)

​ 用于判断输入值类型,如果类型相同,将输入值提取出来。

​ 判断某一个变量是否是某一个类型,如果满足会将该变量存入你申明的变量中。

​ 以前的写法:

if (o is int) {
    int i = (int) o;
    print(i);
}

​ 现在的写法:

if (o is int i) {
    print(i); // 不打印
}

​ switch 使用:

switch (o) {
    case int value:
        print("int:" + value);
        break;
    case float value:
        print("float:" + value); // "float:1.5"
        break;
    case null:
        print("null");
        break;
    default:
        break;
}

(三)var 模式

​ 用于将输入值放入与输入值相同类型的新变量中,相当于是将变量装入一个和自己类型一样的变量中。

if (o is var v) {
    print("v:" + v); // "v:1.5"
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蔗理苦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值