【Unity】Unity C#基础(十六)C#中的? 、?. 、?? 、??=

本文介绍了C#中的可空类型修饰符T?,允许值类型使用空引用,以及空合并运算符??,用于提供默认值。还讲解了?.运算符用于在调用方法或属性前进行非空检查,以及C#8.0引入的??=赋值运算符。示例展示了这些特性的使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


可空类型修饰符 ?

引用类型能用空引用来表示一个不存在的值,但是值类型不能。例如:

string str = null;
int i = null;//编译报错

为了使值类型也能使用可空类型,就可以使用“?”来表示,表现形式为“T?”。例如:

int i?;//表示可控的类型
DataTime time?;//表示可空的时间

T?是System.Nullable的缩写,更便于读取。属于泛型的一种。

空合并运算符 ??

用于定义引用类型和可空类型的默认值。如果此运算符的左操作符不为Null,则此操作符返回左操作数,否则返回右操作数。

//当a不为空时返回a,为null时返回b
var c = a ?? b;

调用函数(或属性)前进行非空验证 ?.

当对象不为null时执行后面的操作。例如:

//两段代码等效
Person.Name?.Person.Code;
Person.Name = Person == null ? null : Person.Code;

??=

C# 8.0 及更高版本中可使用空合并赋值运算符 ??=,该运算符仅在左侧操作数的求值结果为 null 时,才将其右侧操作数的值赋值给左操作数。 如果左操作数的计算结果为非 null,则 ??= 运算符不会计算其右操作数。

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

本文转载自:C#中?、?.、? ?、? ?=的用法和说明,感谢分享。

更多内容请查看总目录【Unity】Unity学习笔记目录整理

<think>好的,我现在需要帮助用户了解C#中可空运算符`?.`的具体用法和示例。用户之前已经询问过JavaScript的可选链运算符,现在转向C#的类似功能。我需要结合用户提供的引用内容,整理出清晰的解释和示例。 首先,我需要确认用户提供的引用内容。引用[1]到[5]都是关于C#中各种可空运算符的,特别是`?.`。引用[3]和[4]详细提到了空条件运算符`?.`的作用,即安全访问对象成员,避免NullReferenceException。引用[5]提到了在Unity中使用时的潜在问题,即使使用`?.`也可能因为后续方法执行导致错误,这可能需要注意。 接下来,我需要组织回答的结构。用户希望知道使用方法和示例。根据之前的回答模式,应该分核心用法、典型场景、注意事项、兼容性等部分。但用户提供的引用中提到了`?.`的用法,以及与其他运算符如`??`的配合使用,还有在Unity中的特殊情况。 首先,核心用法部分需要解释`?.`的基本语法和用途,比如访问对象属性、调用方法、访问集合元素。需要引用[3]和[4]的内容,说明它如何避免NullReferenceException。 然后,典型场景可以包括处理嵌套对象、结合空合并运算符、在LINQ中的应用,以及Unity中的使用。引用[5]提到在Unity中即使使用`?.`也可能报错,需要特别说明注意事项,比如可能存在的延迟销毁问题。 注意事项部分要提到不能用于赋值、短路效应、返回值类型的变化,以及可能的性能影响。引用[5]中的例子显示,在Unity中某些情况下,即使对象为null,`?.`可能无法正确阻止方法执行,需要解释原因,比如Unity的组件销毁机制。 兼容性方面,C# 6.0及以上支持,但Unity版本可能需要检查。引用[5]提到在Unity中的问题,可能需要建议使用特定版本或处理方式。 还需要确保回答中的示例代码正确,并且符合C#语法。比如,使用可空类型时,变量声明需要`?`后缀,如`string? text = null;`。 需要对比JavaScript的可选链运算符,用户之前的问题提到过JS的`?.`,所以在回答中可以简要比较,但重点在C#。例如,C#的`?.`返回null,而JS返回undefined,但行为类似。 最后,生成相关问题,可能需要包括与其他运算符的配合使用、在Unity中的注意事项、与JS的区别等。 现在需要检查是否有遗漏点,比如`?.`在访问数组或索引器时的用法,如`list?[0]`是否正确?根据引用[3],C#中的空条件运算符包括`?[]`,所以应该提到访问集合元素时使用`?[index]`。 另外,引用[2]提到可空类型的运算结果为null,除非使用`??`,所以在结合使用`?.`和`??`时,可以给出示例,如`var result = obj?.Prop ?? defaultValue;`。 在注意事项中,要提到`a?.b.c`和`a?.b?.c`的区别,前者在a.b为null时访问c会抛出异常,后者则安全返回null。这点在引用[3]中有提到。 总结回答结构: 1. 核心用法:属性访问、方法调用、集合访问 2. 典型场景:嵌套对象、结合??、LINQ、Unity 3. 注意事项:不可赋值、短路效应、返回值类型、Unity问题 4. 兼容性:C# 6.0+,Unity版本 5. 示例代码 6. 相关问题 现在需要确保所有引用内容都被合理利用,并且回答准确、清晰。特别是用户提到的Unity中的问题,需要详细说明原因和解决方案,比如使用`?.`时,可能因为Unity的组件被标记为销毁但未完全销毁,导致引用不为null但实际无效,此时需要额外的检查。</think>#### C#可空条件运算符`?.`用法详解 C#中的可空条件运算符`?.`(Null-Conditional Operator)是C# 6.0引入的重要特性,用于简化对可能为`null`的对象成员的安全访问,避免`NullReferenceException`异常[^4]。以下是其核心用法与示例: --- ### 一、核心用法 #### 1. **安全访问对象属性/方法** 当对象可能为`null`时,`?.`会自动短路(short-circuiting),返回`null`而非抛出异常。 **传统写法**: ```csharp if (obj != null && obj.Child != null) { var value = obj.Child.Property; } ``` **使用`?.`简化**: ```csharp var value = obj?.Child?.Property; // 若任一层级为null,返回null[^3] ``` #### 2. **安全调用方法** 若方法所属对象可能为`null`,可直接用`?.`安全调用: ```csharp string? text = null; int? length = text?.Length; // length = null,而非异常[^3] ``` #### 3. **访问集合元素** 结合空条件索引运算符`?[]`,安全访问数组或列表元素: ```csharp List<int>? list = null; int? firstItem = list?[0]; // firstItem = null[^1] ``` --- ### 二、典型场景示例 #### 1. **处理嵌套对象** 解析API响应时,避免深层嵌套的`null`检查: ```csharp string street = response?.Data?.User?.Address?.Street ?? "未知地址"; ``` #### 2. **结合空合并运算符`??`** 为结果提供默认值: ```csharp int age = user?.Profile?.Age ?? 18; // 若任何层级为null,默认返回18[^2] ``` #### 3. **在LINQ查询中使用** 安全处理集合中的可能为`null`的元素: ```csharp var names = users?.Select(u => u?.Name?.ToUpper()) ?? Enumerable.Empty<string>(); ``` #### 4. **Unity开发中的注意事项** Unity中若对象已被标记销毁(如`Destroy(gameObject)`),`?.`可能因延迟释放机制失效,需结合`UnityEngine.Object`判空: ```csharp // 安全写法(Unity专用) if (component != null) { component?.DoSomething(); } ``` --- ### 三、注意事项 1. **不可用于赋值** ```csharp obj?.Property = 10; // 编译错误[^1] ``` 2. **短路效应(Short-Circuiting)** 若`?.`左侧为`null`,右侧表达式不会执行: ```csharp obj?.Method(CalculateValue()); // 若obj为null,CalculateValue()不执行[^4] ``` 3. **返回值类型** `?.`的返回类型为可空类型(`T?`),需显式处理或使用`??`转换: ```csharp int length = text?.Length ?? 0; // 明确处理null情况[^3] ``` 4. **Unity中的特殊行为** Unity的`UnityEngine.Object`重载了`==`运算符,可能导致`?.`误判未完全销毁的对象,建议使用显式判空: ```csharp // Unity推荐写法 if (gameObject != null) { gameObject?.GetComponent<Renderer>().material.color = Color.red; } ``` --- ### 四、兼容性 - **C#版本**:需C# 6.0及以上[^4]。 - **Unity版本**:2018.3+默认支持,旧版本需启用编译器兼容性设置[^5]。 --- #### 示例代码汇总 ```csharp // 示例1:安全访问嵌套属性 class User { public Address? Address { get; set; } } class Address { public string? Street { get; set; } } User? user = GetUser(); string street = user?.Address?.Street ?? "默认街道"; // 示例2:安全调用方法 Action? action = null; action?.Invoke(); // 无操作 // 示例3:集合元素访问 List<int>? numbers = null; int? first = numbers?[0]; // first = null ``` --- ### 相关问题 1. C#中`?.`运算符与`??`运算符如何配合使用? 2.Unity中为何`?.`可能无法完全避免`NullReferenceException`? 3. C#的可空引用类型(Nullable Reference Types)如何与`?.`协同工作? 4. 如何通过编译器配置启用C# 6.0特性(如`?.`)?
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值