当前位置: 首页 > news >正文

C# 空合并操作符(??)不可重载?其实有黑科技可以间接重载!

?? 操作符叫做 null-coalescing operator,即 null 合并运算符。如果此运算符的左操作数不为 null,则此运算符将返回左操作数;否则返回右操作数。

在微软的官方 C# 文档中,此操作符被定义为不可重载。不过我们有方法可以间接实现这样的重载。


本文内容

      • 运算符重载
      • 编写 NullableString 的 ?? 重载
      • 一些注意事项

运算符重载

你可以阅读 C# 中那些可以被重载的操作符,以及使用它们的那些丧心病狂的语法糖 了解 C# 中提供的所有可以重载的操作符。在此文中,?? 被明确定义为不可重载。

你更可以在微软官方文档中找到这样的说法:

  • Overloadable operators (C# Programming Guide)
  • 可重载运算符(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;

相关文章:

  • UWP 轻量级样式定义(Lightweight Styling)
  • 预编译框架,开发高性能应用 - 课程 - 微软技术暨生态大会 2018
  • 将 UWP 中 CommandBar 的展开方向改为向下展开
  • .NET 中创建支持集合初始化器的类型
  • .NET 中让 Task 支持带超时的异步等待
  • .NET/C# 中你可以在代码中写多个 Main 函数,然后按需要随时切换
  • WPF 的 ElementName 在 ContextMenu 中无法绑定成功?试试使用 x:Reference!
  • WPF 中的 NameScope
  • Windows 下的高 DPI 应用开发(UWP / WPF / Windows Forms / Win32)
  • 技术、产品、交流、思考 - 微软技术暨生态大会 2018
  • .NET/C# 反射的的性能数据,以及高性能开发建议(反射获取 Attribute 和反射调用方法)
  • .NET/C# 异常处理:写一个空的 try 块代码,而把重要代码写到 finally 中(Constrained Execution Regions)
  • WindowsXamlHost:在 WPF 中使用 UWP 控件库中的控件
  • WindowsXamlHost:在 WPF 中使用 UWP 的控件(Windows Community Toolkit)
  • .NET/C# 在代码中测量代码执行耗时的建议(比较系统性能计数器和系统时间)
  • 【跃迁之路】【733天】程序员高效学习方法论探索系列(实验阶段490-2019.2.23)...
  • Akka系列(七):Actor持久化之Akka persistence
  • Apache Zeppelin在Apache Trafodion上的可视化
  • extjs4学习之配置
  • input实现文字超出省略号功能
  • js 实现textarea输入字数提示
  • js递归,无限分级树形折叠菜单
  • js数组之filter
  • pdf文件如何在线转换为jpg图片
  • RxJS: 简单入门
  • spring cloud gateway 源码解析(4)跨域问题处理
  • Sublime Text 2/3 绑定Eclipse快捷键
  • 前端攻城师
  • 前端路由实现-history
  • 试着探索高并发下的系统架构面貌
  • 树莓派 - 使用须知
  • 王永庆:技术创新改变教育未来
  • 一天一个设计模式之JS实现——适配器模式
  • 一些基于React、Vue、Node.js、MongoDB技术栈的实践项目
  • 赢得Docker挑战最佳实践
  • 阿里云IoT边缘计算助力企业零改造实现远程运维 ...
  • ​Z时代时尚SUV新宠:起亚赛图斯值不值得年轻人买?
  • #数学建模# 线性规划问题的Matlab求解
  • #我与Java虚拟机的故事#连载09:面试大厂逃不过的JVM
  • $var=htmlencode(“‘);alert(‘2“); 的个人理解
  • (BFS)hdoj2377-Bus Pass
  • (Matlab)遗传算法优化的BP神经网络实现回归预测
  • (三)模仿学习-Action数据的模仿
  • (转)大型网站架构演变和知识体系
  • (转)自己动手搭建Nginx+memcache+xdebug+php运行环境绿色版 For windows版
  • .gitignore文件_Git:.gitignore
  • .NET Conf 2023 回顾 – 庆祝社区、创新和 .NET 8 的发布
  • .NET 线程 Thread 进程 Process、线程池 pool、Invoke、begininvoke、异步回调
  • .NET6 开发一个检查某些状态持续多长时间的类
  • .net开源工作流引擎ccflow表单数据返回值Pop分组模式和表格模式对比
  • .NET项目中存在多个web.config文件时的加载顺序
  • .Net中的集合
  • @ 代码随想录算法训练营第8周(C语言)|Day53(动态规划)
  • [C#] 如何调用Python脚本程序
  • [C++][数据结构][算法]单链式结构的深拷贝