zoukankan      html  css  js  c++  java
  • .NET 欢乐编程术之类型超级转换之术👍👍

      准备工作:先确保 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:转换之后必须显式定义类型,否则将无意义。

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

  • 相关阅读:
    UniEAP V4 开发实践说明文档
    SI_WorkShop_V4安装手册
    unieap platform eclipse.ini vm设置
    asp.net 配置 web.config 禁用VS2013自带的Browser Link功能
    unieap 建库
    onserverclick
    工作中记录的命令和知识点(不断更新)
    CentOS 下做端口映射/端口转发
    DELL服务器硬件信息采集SHELL脚本
    Linux中变量#,@,0,1,2,*,$$,$?的意思
  • 原文地址:https://www.cnblogs.com/Dogwei/p/11243427.html
Copyright © 2011-2022 走看看