?? 操作符叫做 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();

你觉得 value0value1 分别会得到什么呢?

呃……

value0 得到 null,而 value1 得到 ""

另外,如果你将一开始的初始值设为 null,那又可以得到什么结果呢?

NullableString? value = null;
var value0 = value?.ToString();
var value1 = value.ToString();

一样的,value0 得到 null,而 value1 得到 ""

另外,你可以从 null 强转出你需要的类:

var value = (NullableString?) null;

C# 空合并操作符(??)不可重载?其实有黑科技可以间接重载!的更多相关文章

  1. 30天C#基础巩固-----值类型/引用类型,泛型,空合并操作符(??),匿名方法

    一:值类型/引用类型的区别      值类型主要包括简单类型,枚举类型,和结构体类型等,值类型的实例通常被分配在线程堆栈上面变量保存的内容是实例数据本身.引用类型被分配在托管堆上,变量保存的是地址.引 ...

  2. 空合并操作符??(C#)

    ??二元操作符在对first??second求值时,大致会经历以下步骤: 1)对first进行求值: 2)如果结果非空,则该结果就是整个表达式的结果: 3)否则求second的值,其结果作为整个表达式 ...

  3. C# 的可空合并运算符(??)到底是怎样的宝宝?

    前言废语 也怪自己小白和不勤奋,没有系统的学习C#相关的东西,工作一年多还是初级小菜,深感不安,来到园子才发现好多钻研技术的人,也渐渐发现自己开始喜欢上了这个编程的世界.今日偶遇??操作符,发现我只看 ...

  4. PHP——??空合并运算符和?:三元运算符

    前言 在上一篇随笔,用三元运算符简单写的一个东西,引发了对他的兴趣,所以打算研究下. PHP7的新特性: https://php.net/manual/zh/migration70.new-featu ...

  5. C# 空合并运算符 ??

    C#语言中,??运算符称为空合并运算符: a??b形式的空合并表达式要求a为可以为null的类型或引用类型.如果a为非null,则a??b的结果为a:否则,结果为b.仅当a为null时,该操作才计算b ...

  6. .net 空接合操作符 ??

    C# 提供了一个所谓的 ”空接合操作符“ - 即??操作符,他要获取两个操作数. 假如左边的操作数部位null,就返回这个操作数.如果左边的操作数为null就返回右边. 空接合操作符一个妙处在于,它既 ...

  7. RxJava2实战---第七章 合并操作符和连接操作符

    RxJava2实战---第七章 合并操作符和连接操作符 RxJava的合并操作符: startWith():在数据序列的开头增加一项数据. merge:将多个Observable合并为一个. merg ...

  8. NULL合并操作符??

    参考官方手册: /** * NULL合并操作符 ?? */ // $a, $b, $c都未声明和定义 var_dump($a??$b??$c); // NULL // $a为数组,$b为100,$c为 ...

  9. C++ 函数重载,函数模板和函数模板重载,选择哪一个?

    重载解析 在C++中,对于函数重载.函数模板和函数模板重载,C++需要有一个良好的策略,去选择调用哪一个函数定义(尤其是多个参数时),这个过程称为重载解析. (这个过程将会非常复杂,但愿不要遇到一定要 ...

随机推荐

  1. array2xml xml2array

    array2xml/**     *     * 将简单数组转化为简单的xml     * @param string $data  要进行转化的数组     * @param string $tag ...

  2. 特定于类的内存管理---《C++必知必会》 条款36

    我们可以量身定制 operator new 和 operator delete 用于某个类类型,而不是必须使用标准版的 operator new 和 operator delete. 注意:我们不可以 ...

  3. Js中的filter()方法

    /* filter()方法使用指定的函数测试所有元素,并创建一个包含所有通过测试的元素的新数组. filter()基本语法: arr.filter(callback[, thisArg]) filte ...

  4. nats

    NATS is a family of open source products that are tightly integrated but can be deployed independent ...

  5. springboot+mybatis项目自动生成

    springboot_data_access_demo基于rapid,根据自定义模版生成的基于mybatis+mysql的数据库访问示例项目.简单配置数据库信息,配置不同的生成策略生成可以直接运行访问 ...

  6. Sybase数据库第三方软件安装

    Sybase数据库第三方软件安装 1,安装软件:IQNC160011P_1-20011253.ZIP

  7. Tinkoff Challenge - Elimination Round D. Presents in Bankopolis(区间DP)

    http://codeforces.com/contest/793/problem/D 题意:给出一些点和他们之间的距离,是有向的,这些点从1~n顺序排列,现在选出k个点组成一条路径,使他们之间的距离 ...

  8. BZOJ 1951 【SDOI2010】 古代猪文

    题目链接:古代猪文 好久没写博客了,这次就先写一篇吧…… 题面好鬼……概括起来就是:给出\(N,G(\leqslant 10^9)\),求:\[G^{\sum_{d|n}\binom{n}{d}} \ ...

  9. 获取主机的对外ip

    # curl -w "\n" ifconfig.me # curl -w "\n" ipinfo.io/json # curl -w "\n" ...

  10. Qt532_WebKit_SSL问题

    1.打开网页"http://www.baidu.com",它会跳转至"https://www.baidu.com/",使用 SSL了,于是 WebView 出现 ...