C# 空合并操作符(??)不可重载?其实有黑科技可以间接重载!
?? 操作符叫做 null-coalescing operator,即 null 合并运算符。如果此运算符的左操作数不为 null,则此运算符将返回左操作数;否则返回右操作数。
在微软的官方 C# 文档中,此操作符被定义为不可重载。不过我们有方法可以间接实现这样的重载。
运算符重载
你可以阅读 C# 中那些可以被重载的操作符,以及使用它们的那些丧心病狂的语法糖 了解 C# 中提供的所有可以重载的操作符。在此文中,?? 被明确定义为不可重载。
你更可以在微软官方文档中找到这样的说法:
=, ., ?:, ??, ->, =>, f(x), as, checked, unchecked, default, delegate, is, new, sizeof, typeof
These operators cannot be overloaded.
这些运算符无法进行重载。
编写 NullableString 的 ?? 重载
我们先写一个空壳子。连构造函数都是 private 的,这个类当然几乎不可用啦。
特别注意,我们的 Walterlv.NullableString 用的是 struct 类型,这样能与 Nullable<T> 的用法上接近。也就是说,我们可以确保其值实际上永不为 null。
namespace Walterlv
{
public struct NullableString
{
private readonly string _value;
private NullableString(string value)
{
_value = value;
}
}
}
现在我们挑战一下官方说好了不能重载的 ?? 重载(作死):
![试着重载 ??]](https://img-blog.csdn.net/20180926211208502?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1dQd2FsdGVy/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
▲ 试着重载 ??
很明显,既不是可重载的一员运算符也不是可重载的二元运算符。
现在我们试试隐式转换:
public static implicit operator NullableString(string value)
{
return new NullableString(value);
}
public static implicit operator string(NullableString nullableString)
{
return nullableString._value;
}
然而这样的写法实际上并无实际用途。
但是,我们可以在 NullableString 后面加上 ?:
public static implicit operator NullableString?(string value)
{
return string.IsNullOrEmpty(value) ? (NullableString?) null : new NullableString(value);
}
public static implicit operator string(NullableString? nullableString)
{
return nullableString?.ToString() ?? string.Empty;
}
也就是说,C# 竟然允许隐式转换的时候,参数和返回值都不是此类型。当然,实际上这只对 Nullable<T> 生效,如果你试图写别的类型,是不可以的。
为了方便,我们重写一下 ToString(),部分场景下可以代替隐式转换,少写一些代码。
public override string ToString()
{
return string.IsNullOrEmpty(_value) ? string.Empty : _value;
}
于是,我们的 NullableString 类型的完整代码如下:
namespace Walterlv
{
public readonly struct NullableString
{
private readonly string _value;
private NullableString(string value)
{
_value = value;
}
public static implicit operator NullableString?(string value)
{
return string.IsNullOrEmpty(value) ? (NullableString?) null : new NullableString(value);
}
public static implicit operator string(NullableString? nullableString)
{
return nullableString?.ToString() ?? string.Empty;
}
public override string ToString()
{
return string.IsNullOrEmpty(_value) ? string.Empty : _value;
}
}
}
注释就你自己添加吧。
一些注意事项
这里有一些好玩的事情需要分享。比如我们写出如下代码:
NullableString? value = "";
var value0 = value?.ToString();
var value1 = value.ToString();
你觉得 value0 和 value1 分别会得到什么呢?
呃……
value0 得到 null,而 value1 得到 ""。
另外,如果你将一开始的初始值设为 null,那又可以得到什么结果呢?
NullableString? value = null;
var value0 = value?.ToString();
var value1 = value.ToString();
一样的,value0 得到 null,而 value1 得到 ""。
另外,你可以从 null 强转出你需要的类:
var value = (NullableString?) null;
C# 空合并操作符(??)不可重载?其实有黑科技可以间接重载!的更多相关文章
- 30天C#基础巩固-----值类型/引用类型,泛型,空合并操作符(??),匿名方法
一:值类型/引用类型的区别 值类型主要包括简单类型,枚举类型,和结构体类型等,值类型的实例通常被分配在线程堆栈上面变量保存的内容是实例数据本身.引用类型被分配在托管堆上,变量保存的是地址.引 ...
- 空合并操作符??(C#)
??二元操作符在对first??second求值时,大致会经历以下步骤: 1)对first进行求值: 2)如果结果非空,则该结果就是整个表达式的结果: 3)否则求second的值,其结果作为整个表达式 ...
- C# 的可空合并运算符(??)到底是怎样的宝宝?
前言废语 也怪自己小白和不勤奋,没有系统的学习C#相关的东西,工作一年多还是初级小菜,深感不安,来到园子才发现好多钻研技术的人,也渐渐发现自己开始喜欢上了这个编程的世界.今日偶遇??操作符,发现我只看 ...
- PHP——??空合并运算符和?:三元运算符
前言 在上一篇随笔,用三元运算符简单写的一个东西,引发了对他的兴趣,所以打算研究下. PHP7的新特性: https://php.net/manual/zh/migration70.new-featu ...
- C# 空合并运算符 ??
C#语言中,??运算符称为空合并运算符: a??b形式的空合并表达式要求a为可以为null的类型或引用类型.如果a为非null,则a??b的结果为a:否则,结果为b.仅当a为null时,该操作才计算b ...
- .net 空接合操作符 ??
C# 提供了一个所谓的 ”空接合操作符“ - 即??操作符,他要获取两个操作数. 假如左边的操作数部位null,就返回这个操作数.如果左边的操作数为null就返回右边. 空接合操作符一个妙处在于,它既 ...
- RxJava2实战---第七章 合并操作符和连接操作符
RxJava2实战---第七章 合并操作符和连接操作符 RxJava的合并操作符: startWith():在数据序列的开头增加一项数据. merge:将多个Observable合并为一个. merg ...
- NULL合并操作符??
参考官方手册: /** * NULL合并操作符 ?? */ // $a, $b, $c都未声明和定义 var_dump($a??$b??$c); // NULL // $a为数组,$b为100,$c为 ...
- C++ 函数重载,函数模板和函数模板重载,选择哪一个?
重载解析 在C++中,对于函数重载.函数模板和函数模板重载,C++需要有一个良好的策略,去选择调用哪一个函数定义(尤其是多个参数时),这个过程称为重载解析. (这个过程将会非常复杂,但愿不要遇到一定要 ...
随机推荐
- 索引查找Java实现
package 索引查找; import java.util.Scanner; public class IndexSearch { public static long stu[] = { 1080 ...
- 安装memcached扩展 验证过了可行
. 安装libmemached 复制代码 代码如下: wget https://launchpad.net/libmemcached/1.0/1.0.16/+download/libmemcached ...
- 字节跳动冬令营网络赛 Solution
A:Aloha Unsolved. B:Origami Unsolved. 题意: 初始的时候有一张纸,可以从左边往右边折叠,或者从右边往左边折叠 每次折叠的长度不能超过现有宽度,最后折叠到长度为1 ...
- react 修改循环列表的当前单个子项状态:思路 拿原始state数据更改,再做请求
handleLike(item,index){ var id = item.id; _ENV.post( _ENV.HOST+'/communion/video-up', {'user_id':loc ...
- linux 导入导出mysql相关问题
linux 导入mysql报错 CREATE DATABASE `mmm` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; CREATE D ...
- 一个Golang例子:for + goroutine + channel
Rob Pike 在 Google I/O 2012 - Go Concurrency Patterns 里演示了一个例子(daisy chain). 视频地址:https://www.youtube ...
- 2018-2019-1 20189218《Linux内核原理与分析》第三周作业
mykernel 实验 实验楼里按步骤运行一切顺利,make等待的时间特别久: 但是,启动mykernel后,实验楼的界面就不响应了,所以还是在自己虚拟机上做这个实验. 虚拟机搭建 mykernel ...
- linux中readl()和writel()函数---用于读写寄存器
writel() 往内存映射的 I/O 空间上写数据,wirtel() I/O 上写入 32 位数据 (4字节). 原型: #include <asm/io.h> void writel ...
- 数据库常见的三种join方式
数据库常见的join方式有三种:inner join, left outter join, right outter join(还有一种full join,因不常用,本文不讨论).这三种连接方式都是将 ...
- SpringBoot与Dubbo整合上篇
最近学习了一下dubbo,是阿里巴巴公司的一个开源服务框架.目前我们公司实现两个不同系统的之间通信,是采用了Oracle的OSB作为服务的管理(即企业服务总线的一种实现),服务提供方在OSB上注册业务 ...