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++需要有一个良好的策略,去选择调用哪一个函数定义(尤其是多个参数时),这个过程称为重载解析. (这个过程将会非常复杂,但愿不要遇到一定要 ...
随机推荐
- SpringData环境搭建代码编写
首先我们在前面的两节已经了解了SpringData是干什么用的?那我们从这节开始我们就开始编码测试SpringData. 1:首先我们从配置文件开始,我们首先需要写一个连接数据库的文件db.prope ...
- uva1291
这题说的给了 一 个 图,每次 按照他给的顺序 跳格子 给了 每种 格子之间的 转换 代价 求最后 转换代价 dp[i][j] 表示 左脚在i 右脚 在j 的最小代价 然后用滚动数组 ,就可以不断说的 ...
- Python: 字符串格式化format()函数的使用
python从2.6开始支持format,新的更加容易读懂的字符串格式化方法,从原来的% 模式变成新的可读性更强的 花括号声明{}.用于渲染前的参数引用声明, 花括号里可以用数字代表引用参数的序号, ...
- jQuery获取不到隐藏DIV的高度和宽度
今天做公司订单系统的修改,有同事将订单维护的四个部分拆成了四个小的tab页,由于数据表格时动态加载,所以表格的高度是动态变化的,可不知怎么,先点哪个哪个的高度就正常,其他的都是最小值,这下蒙了,这个找 ...
- vue.js指令v-model实现方法
原文链接:http://www.jb51.net/article/99097.htm V-MODEL 是VUE 的一个指令,在input 控件上使用时,可以实现双向绑定. 通过看文档,发现他不过是一个 ...
- MSF基础攻击实践报告
MSF基础攻击实践 MSF的六个模块:exploit,encoder,payload,aux,post,nops exploit——渗透攻击模块 测试者利用它来攻击一个系统,程序,或服务,以获得开发者 ...
- 各版本的区别及含义(i386 、x86_64 、ppc )
1.i386:是指兼容Intel 80386处理器 x86或80x86是英代爾Intel首先开发制造的一种微处理器体系结构的泛称.該系列較早期的處理器名稱是以數字來表示,並以“86”作為結尾, ...
- HDU 3709 Balanced Number(数位DP)题解
思路: 之前想直接开左右两边的数结果爆内存... 枚举每次pivot的位置,然后数位DP,如果sum<0返回0,因为已经小于零说明已经到了pivot右边,继续dfs只会越来越小,且dp数组会炸 ...
- git squash 和 git rebase
In git, what is the difference between merge --squash and rebase? 上面链接的回答中的总结: Both git merge --squa ...
- SPOJ—VLATTICE Visible Lattice Points(莫比乌斯反演)
http://www.spoj.com/problems/VLATTICE/en/ 题意: 给一个长度为N的正方形,从(0,0,0)能看到多少个点. 思路:这道题其实和能量采集是差不多的,只不过从二维 ...