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

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

  • 相关阅读:
    VS2008编写MFC程序--使用opencv2.4()
    November 02nd, 2017 Week 44th Thursday
    November 01st, 2017 Week 44th Wednesday
    October 31st, 2017 Week 44th Tuesday
    October 30th, 2017 Week 44th Monday
    October 29th, 2017 Week 44th Sunday
    October 28th, 2017 Week 43rd Saturday
    October 27th, 2017 Week 43rd Friday
    October 26th, 2017 Week 43rd Thursday
    October 25th, 2017 Week 43rd Wednesday
  • 原文地址:https://www.cnblogs.com/Dogwei/p/11243427.html
Copyright © 2011-2022 走看看