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++需要有一个良好的策略,去选择调用哪一个函数定义(尤其是多个参数时),这个过程称为重载解析. (这个过程将会非常复杂,但愿不要遇到一定要 ...
随机推荐
- 文字和图片居中的HTML代码怎么写?
HTML 代码 ,怎么将文本/ 图片居中?这是在W3Cschool的编程问答中前端♌蕾儿提出的问题.网友施主同西否给出了详细的解答. html文字居中和html图片居中方法代码,通过在html中实现文 ...
- oracle数据库中导入Excel表格中的数据
1.点击[工具]-->[ODBC 导入器],如图: 2.在导入器里选择第一个[来自ODBC的数据],用户名/系统DSN-->填写[Excel Files],输入用户名和密码,点击 [连接] ...
- 20145325张梓靖 《Java程序设计》第8周学习总结
20145325张梓靖 <Java程序设计>第8周学习总结 教材学习内容总结 Logger java.util.logging包提供了日志功能相关类与接口,使用日志的起点是logger类, ...
- 20172305 2018-2019-1 《Java软件结构与数据结构》第五周学习总结
20172305 2018-2019-1 <Java软件结构与数据结构>第五周学习总结 教材学习内容总结 本周内容主要为书第九章内容: 查找是在某个项目组中寻找到某一指定目标元素,或者确定 ...
- ngular6开发不完全笔记(三)-- 报错指南
router Uncaught Error: Template parse errors: 'router-outlet' is not a known element: If 'router-out ...
- ubuntu 16.04+Anaconda+theano+keras安装【转】
本文转载自:https://blog.csdn.net/u013786021/article/details/78370138 安装软件部分浪费了好长时间才装好.之前一直各种问题,后来卸卸了radin ...
- Exception.StackTrace
Exception中的StackTrace属性 执行堆栈跟踪在给定时刻正在执行的所有方法. 对方法调用的跟踪称为堆栈跟踪. 堆栈跟踪列表提供了一种循着调用堆叠跟踪到方法中异常发生处行号的手段.Stac ...
- Python学习札记(三十八) 面向对象编程 Object Oriented Program 9
参考:多重继承 NOTE #!/usr/bin/env python3 class Animal(object): def __init__(self, name): self.name = name ...
- Codeforces Round #408 (Div. 2) C. Bank Hacking
http://codeforces.com/contest/796/problem/C Although Inzane successfully found his beloved bone, Zan ...
- VuePress从零开始搭建自己的博客
VuePress是什么? VuePress是以Vue驱动的静态网站生成器,是一个由Vue.Vue Router和webpack驱动的单页应用.在VuePress中,你可以使用Markdown编写文档, ...