zoukankan      html  css  js  c++  java
  • C# ValueTuple 原理

    本文告诉大家一些 ValueTuple 的原理,避免在使用出现和期望不相同的值。ValueTuple 是 C# 7 的语法糖,如果使用的 .net Framework 是 4.7 以前,那么需要使用 Nuget 安装System.ValueTuple

    虽然 ValueTuple 的很好用,但是需要知道他有两个地方都是在用的时候需要知道他原理。如果不知道原理,可能就发现代码和预期不相同

    json 转换

    先创建一个项目,然后安装 Json 解析,使用下面的代码,在运行之前,先猜一下,下面的代码会出现什么

                var foo = (name: "lindexi", site: "blog.csdn.net/lindexi_gd");
                var str = JsonConvert.SerializeObject(foo);
    

    实际上输出的是 {"Item1":"lindexi","Item2":"blog.csdn.net/lindexi_gd"}

    那么刚才的命名在哪?

    如果想知道,那么请看 ValueTuple 的原理

    原理

    先来写一段代码,编译之后对他反编译,看一下他是怎么做的

            static void Main(string[] args)
            {
                var foo = Foo();
                var str = JsonConvert.SerializeObject(foo);
                Console.WriteLine(str);
            }
    
            static (string name, string site) Foo()
            {
                return (name: "lindexi", site: "blog.csdn.net/lindexi_gd");
            }
    

    不需要安装反编译软件,可以使用这个网站拿到反编译

    可以看到Foo被编译为 TupleElementNames 特性的两个字符串

        [return: TupleElementNames(new string[]
        {
            "name",
            "site"
        })]
        private static ValueTuple<string, string> Foo()
        {
            return new ValueTuple<string, string>("lindexi", "blog.csdn.net/lindexi_gd");
        }
    

    所以实际上代码是 ValueTuple<string, string> 不是刚才定义的代码,只是通过 TupleElementNames 让编译器知道值,所以是语法糖。

    IL 代码是

    private hidebysig static valuetype [mscorlib]System.ValueTuple`2<string, string> 
        Foo() cil managed 
      {
        .param [0] 
        .custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) 
          = (
            01 00 02 00 00 00 04 6e 61 6d 65 04 73 69 74 65 // .......name.site 这里就是 return: TupleElementNames 的命名
            00 00                                           // ..
          )
        .maxstack 2
        .locals init (
          [0] valuetype [mscorlib]System.ValueTuple`2<string, string> V_0
        )
    
        // [20 9 - 20 10]
        IL_0000: nop          
    
        // [21 13 - 21 72]
        IL_0001: ldstr        "lindexi"
        IL_0006: ldstr        "blog.csdn.net/lindexi_gd"
        IL_000b: newobj       instance void valuetype [mscorlib]System.ValueTuple`2<string, string>::.ctor(!0/*string*/, !1/*string*/)
        IL_0010: stloc.0      // V_0
        IL_0011: br.s         IL_0013
    
        // [22 9 - 22 10]
        IL_0013: ldloc.0      // V_0
        IL_0014: ret          
    
      }
    

    这个特性只有编译器可以用,不可以在代码使用。

    在上面的解释,实际上 IL 不知道存在定义的命名,所以不可以通过这个方法获得值。

    动态类型获得值

    如果希望使用动态类型获得值,那么下面的代码实际上会运行出现异常

            static void Main(string[] args)
            {
                dynamic foo = Foo();
                Console.WriteLine(foo.name);
            }
    
            static (string name, string site) Foo()
            {
                return (name: "lindexi", site: "blog.csdn.net/lindexi_gd");
            }
    

    运行出现 RuntimeBinderException 异常,因为没有发现 name 属性

    实际上对比下面匿名类,也就是很差不多写法。

            dynamic foo = new { name = "lindexi", site = "blog.csdn.net/lindexi_gd" };
                Console.WriteLine(foo.name);
    

    运行是可以的,所以在使用动态类型,请不要使用 ValueTuple ,如果需要使用,那么请知道有存在找不到变量异常,而且是在运行才出现异常。

    其他需要知道的

    不要随便定义一个看不懂的值

    实际上下面的代码,编译是可以通过

    (int x, (int y, (float a, float b))[] c) f1
    

    但是这个值,在看的时候,几乎说不出他的属性

    第二个需要知道的,ValueTuple 是值类型,所以他的默认值不是 null 而是 default(xx),在C# 7.2 支持使用关键字,所以不需要去写 defalut(xx,xx)

    关于 ValueTuple 变量名的定义也是很难说的,有的小伙伴觉得需要使用 Axx 的方式命名,但是很多小伙伴觉得使用 aaBa 的命名更好,所以暂时对于他的命名,大家觉得什么方式好请告诉我

    参见: Exploring Tuples as a Library Author

    C# 7: Dynamic types and Reflection cannot access Tuple fields by name

    我搭建了自己的博客 https://lindexi.gitee.io/ 欢迎大家访问,里面有很多新的博客。只有在我看到博客写成熟之后才会放在csdn或博客园,但是一旦发布了就不再更新

    如果在博客看到有任何不懂的,欢迎交流,我搭建了 dotnet 职业技术学院 欢迎大家加入

    知识共享许可协议
    本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系

  • 相关阅读:
    更改PHP配置文件php.ini解决xmlhttp的utf8乱码
    php 单引号 双引号 区别
    zend soap looks like we got no XML document
    使用UltraEdit32编辑器格式化源码功能 XML、Java、C/C++、C#
    php str_replace 单引号 双引号 区别
    PHP将XML文件转换成PHP数组
    简述PHP4和PHP5版本下解析XML文档的操作方法
    HowTo: Fix SimpleXML CDATA problem in php
    XML中 CDATA and PCDATA 的区别
    php 生成xml 的四种方式
  • 原文地址:https://www.cnblogs.com/lindexi/p/csharp-valuetuple.html
Copyright © 2011-2022 走看看