准备工作:先确保 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 = ;

Console.WriteLine(str); // Output : Dogwei

myStr._stringLength = ;

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[]; var say = splits[]; 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[]; var say = splits[]; Console.WriteLine($"Hello! my name is {name}, I am {say}.");
}
}

  执行程序后什么也没发生,既没执行,也没报错:

  到这里相信大家也对类型强转超级之术有一点理解,但是这个“巫术”有一些限制:

  1:不能转换为值类型!

  2:转换之后必须显式定义类型,否则将无意义。

  下一章我们将讲超级转换之术二代!可以转换任何对象,且是实际意义转换。

.NET 欢乐编程术之类型超级转换之术👍👍的更多相关文章

  1. C#高级编程笔记 2016年10月8日运算符和类型强制转换

    1.checked和unchecked 运算符 C#提供了checked 和uncheckde 运算符.如果把一个代码块标记为checked, CLR就会执行溢出检查,如果发生溢出,就抛出overfl ...

  2. C#高级编程9-第7章 运算符和类型强制转换

    运算符和类型强制转换 1.运算符 运算符的简化操作 条件运算符: if-else的简化操作,也称三元运算符.如果条件为真,返回一个值,为假返回另外一个值. condition?true_value:f ...

  3. C#高级编程 (第六版) 学习 第六章:运算符和类型强制转换

    第六章 运算符和类型强制转换 1,运算符 类别 运算符 算术运算符 + - * / % 逻辑运算符 & | ^ ~ && || ! 字符串连接运算符 + 增量和减量运算符 ++ ...

  4. 【读书笔记】C#高级编程 第七章 运算符和类型强制转换

    (一)运算符 类别 运算符 算术运算符 + - * / % 逻辑运算符 & | ^ ~ && || ! 字符串连接运算符 + 增量和减量运算符 ++ -- 移位运算符 < ...

  5. 【转】java中byte数组与int类型的转换(两种方式)----不错

    原文网址:http://blog.csdn.net/piaojun_pj/article/details/5903009 java中byte数组与int类型的转换,在网络编程中这个算法是最基本的算法, ...

  6. C语言指针类型 强制转换

    关于C语言指针类型 强制转换  引用一篇文章: C语言中,任何一个变量都必须占有一个地址,而这个地址空间内的0-1代码就是这个变量的值.不同的数据类型占有的空间大小不一,但是他们都必须有个地址,而这个 ...

  7. C++四种类型的转换

    在C/C++使用的语言 (type) value(您还可以使用type(value))对于显式类型转换,经常提到投.转换程序猿的精度等完全掌握手,一个传统投往往是过度使用.成为C++要根源. 为了降低 ...

  8. 《Python核心编程》数字类型

    1.数字类型简单介绍 Python中数字类型包含:整型.长整型.布尔型.双精度浮点型.十进制浮点型.复数.这些数字类型都是不可变类型.也就是说,改变了数字的值会生成新的对象. 在Python中删除数字 ...

  9. FILETIME类型到LARGE_INTEGER类型的转换

    核心编程第5版 245页到247页的讲到SetWaitableTimer函数的使用 其中提到 FILETIME类型到LARGE_INTEGER类型的转换问题,如下代码 //我们声明的局部变量 HAND ...

随机推荐

  1. Debug监视器(监视运行期程序通过API函数OutputDebugString输出的字符串)

    http://download.csdn.net/detail/zswang/207199

  2. Adobe cs6 全系列软件绿色破解版-一键安装

    下载地址: 链接:https://pan.baidu.com/s/1THssmSS-SnyNc2DW7Wr8cA 提取码:y3tq 软件介绍 作为全球领先的多媒体设计软件供应商,Adobe Syste ...

  3. chrome浏览器开发者工具F12中某网站的sources下的源码如何批量保存?

    目录 chrome浏览器 开发者工具F12中某网站的sources下的源码如何批量保存 1. 常用保存Sources源码的两种方法 1.1单个文件 1.2 单个页面 2. 问题 3.解决方案 chro ...

  4. PWN菜鸡入门之函数调用栈与栈溢出的联系

    一.函数调用栈过程总结 Fig 1. 函数调用发生和结束时调用栈的变化 Fig 2. 将被调用函数的参数压入栈内 Fig 3. 将被调用函数的返回地址压入栈内 Fig 4. 将调用函数的基地址(ebp ...

  5. Programming In Lua 第一章

    1,Lua可以嵌入其他应用程序(如CGILua或IUPLua). 2,lua代码的语句,分号是可以省略的.同一行可以有多条lua语句,最好用分号隔开(当然也可以不隔开) 3,外壳与lua解释器的区别. ...

  6. kafka入门(三)备份

    一.相关概念 备份相关的角色 Kafka消息备份分三个角色:分别是Leader副本.Follower副本.ISR集合 Leader副本 负责直接响应client端的读写请求,即和生产者和消费者直接对接 ...

  7. Codeforces Gym100543L:Outer space invaders(区间DP)

    题目链接 题意 有n个人,每个人有一个出现时间a和一个开枪时间b和一个距离d,在任意一个时刻,你可以选择炸人,你要炸一个人的花费是和他的距离d,并且所有的已经出现并且还没开枪的和你距离<=d的人 ...

  8. 性能测试即服务-docker部署jmeter及.netcore应用

    前言 现在各种业务都追求上云,通俗的讲,“XX即服务”,作为一名专职的性能测试调优人员的我,由于会点三脚猫的开发功夫,“性能测试即服务”这种开发大任就落到我头上了,先做一个能完成核心压测功能的基础版. ...

  9. redis module 学习—官网文档整理

    前言 redis在4.0版本中,推出了一个非常吸引的特性,可以通过编写插件的模式,来动态扩展redis的能力.在4.0之前,如果用户想拥有一个带TTL的INCRBY 命令,那么用户只能自己去改代码,重 ...

  10. MySQL login-path 本地快捷登陆

    目录 1.什么是 login-path 2. 配置 login-path 2.2.配置: 2.3.显示配置: 2.3.1.显示执行的login-path配置 2.3.2.显示所有的login-path ...