.NET 欢乐编程术之类型超级转换之术👍👍
2019-07-25 12:08
1796 查看
准备工作:先确保 VS 版本大于 2017,且支持C# 7.0 语言版本。然后新建 .Net Core 项目,在 Nuget 包管理上引入微软霸霸官方包 System.Runtime.CompilerServices.Unsafe。此包提供了非常底层又符合 .Net CLR 的 API,包括操作指针,引用,内存的方法。
接下来我们就可以利用这个包,去获取一个字符串的内存信息,然后更改这个字符串的内容。众所周知,.Net 中的字符串是不可变的,C# 和 .Net 都极大的限制程序员不可修改字符串的内容,因为一旦修改了字符串的内容,将破环 CLR 的规则,使得程序变得不稳定。
首先我们定义一个与 String 类型字段结构完全一样的类型:
public sealed class MyString { /// <summary> /// 字符串的长度。 /// </summary> public int _stringLength; /// <summary> /// 字符串第一个字符,它与后续的字符的内存是连续的。 /// </summary> public char _firstChar; }
然后我们定义一个字符串:
var str = "Dogwei 牛B!";
然后我们将这个字符串超级转换为 MyString 类型:
var myStr = System.Runtime.CompilerServices.Unsafe.As<MyString>(str);
现在我们可以修改字符串的内容了:
var str = "Dogwei 牛B!"; var myStr = System.Runtime.CompilerServices.Unsafe.As<MyString>(str); Unsafe.Add(ref myStr._firstChar, str.IndexOf('牛')) = 'S'; Console.WriteLine(str); // Output : Dogwei SB!
怎么样,是不是很有意思?我们再来试试修改字符串长度:
myStr._stringLength = 6; Console.WriteLine(str); // Output : Dogwei myStr._stringLength = 999; Console.WriteLine(str); // Dogwei SB! ??翽 鄈淭翽...
长度超过字符串本来的长度会输出一串乱码。
同样转换之后的方法也是可以执行的:
public class Demo { public static void Main() { var str = "Dogwei 牛B!"; var myStr = Unsafe.As<MyString>(str); myStr.SayHello(); } } public sealed class MyString { /// <summary> /// 字符串的长度。 /// </summary> public int _stringLength; /// <summary> /// 字符串第一个字符,它与后续的字符的内存是连续的。 /// </summary> public char _firstChar; public void SayHello() { var str = Unsafe.As<string>(this); var splits = str.Split(' '); var name = splits[0]; var say = splits[1]; Console.WriteLine($"Hello! my name is {name}, I am {say}."); } }
但是执行方法有一个必须要注意的地方,就是执行的方法必须是最终方法!(何为最终方法请查阅微软官方文档 System.Reflection.MethodInfo.IsFinal)。如果不是最终方法会怎么样呢?我们来试试:
同上例,Main 方法保持不变,修改 MyString 为如下:
public class MyString { /// <summary> /// 字符串的长度。 /// </summary> public int _stringLength; /// <summary> /// 字符串第一个字符,它与后续的字符的内存是连续的。 /// </summary> public char _firstChar; public virtual void SayHello() { var str = Unsafe.As<string>(this); var splits = str.Split(' '); var name = splits[0]; var say = splits[1]; Console.WriteLine($"Hello! my name is {name}, I am {say}."); } }
执行程序后什么也没发生,既没执行,也没报错:
到这里相信大家也对类型强转超级之术有一点理解,但是这个“巫术”有一些限制:
1:不能转换为值类型!
2:转换之后必须显式定义类型,否则将无意义。
下一章我们将讲超级转换之术二代!可以转换任何对象,且是实际意义转换。
相关文章推荐
- .NET学习笔记(三) ------系统类型和通用操作 (下)
- 浅析.NET中的引用类型和值类型(上)
- .NET提供了哪几个定时器类型
- .net 中 ActionResult 返回类型
- biztalk中使用.net class类型的消息(一) -- 相关知识介绍【转】
- [转]6个重要的.NET概念:栈,堆,值类型,引用类型,装箱,拆箱
- Win32类型和.net类型的对应表 选择自 AppleDotnet 的 Blog
- WCF Data Service 的.NET Client 的不支持原生类型服务操作的解决方法
- WCF Data Service 的.NET Client 的不支持原生类型服务操作的解决方法
- WCF Data Service 的.NET Client 的不支持原生类型服务操作的解决方法
- WCF Data Service 的.NET Client 的不支持原生类型服务操作的解决方法
- [.NET] : 设定Windows Service启动类型
- .NET 指南:类型构造器的设计
- .NET程序开发中必须收藏的七个类型的经典工具
- [.Net码农]如何在ASP.NET的web.config配置文件中添加MIME类型
- .NET中三种数据类型转换的区别:(type), type.Parse, Convert类
- .NET : 如何动态根据一个业务实体类型创建XSD架构文件
- CH4 类型基础 .net 复习课
- .net调用java webService返回类型是空
- .NET 数据类型概述