【问题标题】:Is this valid C# code?这是有效的 C# 代码吗?
【发布时间】:2011-10-19 10:53:16
【问题描述】:

这是有效的 C# 代码吗?

  public class Product
  {
        [CompilerGenerated]
        private string <Name>k__BackingField;

    [CompilerGenerated]
    private decimal <Price>k__BackingField;

    public string Name
    {
     get;
     private set;
    }

    public decimal Price
    {
     get;
     private set;
    }

    public Product() 
        {
        }

    public static List<Product> GetSampleProducts()
    {
     List<Product> products = new List<Product>();
     Product num1.Price = new decimal(1233, 0, 0, false, 2).Add(num1);
     Product product1.Price = new decimal(1332, 0, 0, false, 2).Add(product1);
     Product num2.Price = new decimal(2343, 0, 0, false, 2).Add(num2);
     Product product2.Price = new decimal(2355, 0, 0, false, 2).Add(product2);
     return products;
    }

    public override string ToString()
    {
     return string.Format("{0}: {1}", this.Name, this.Price);
    }
   }

上面的例子取自 JustDecompile(一个 .NET 反编译器),你可以在下面看到原始版本:

using System;
using System.Collections.Generic;
using System.Text;

namespace ProductV3
{
   public class Product
   {
       public string Name { get; private set; }
       public decimal Price { get; private set; }

       public Product() { }

       public static List<Product> GetSampleProducts()
       {
          return new List<Product>()
          {
              new Product() { Name = "ProductA", Price = 12.33M },
              new Product() { Name = "ProductB", Price = 13.32M },
              new Product() { Name = "ProductC", Price = 23.43M },
              new Product() { Name = "ProductD", Price = 23.55M }
          };
       }

       public override string ToString()
       {
          return string.Format("{0}: {1}", Name, Price);
       }
   }
}

我想知道第一个列表是反编译错误还是编译器生成的有效 C# 代码。我非常好奇 GetSampleProducts 方法中的代码是什么。

【问题讨论】:

  • 产品名称哪里去了?
  • 一个明显非法的部分由自动生成的标识符组成,其中包含 C# 不允许在标识符中使用的字符,但 CLR 允许。
  • 你可以通过编译来判断它是否有效...
  • 就像它所说的,只需将其通过编译器进行验证即可。至于它是否会做同样的事情,据我所知,我认为不会。就像 David Heffernan 说的那样,缺少产品名称,您也完全缺少第二个 2 示例产品。

标签: c# .net compiler-construction decompiler


【解决方案1】:

通过将其粘贴到编译器并尝试编译它很容易看出它不是有效的 C# 代码。

反编译器似乎不知道如何正确处理自动属性和对象字面量语法(不确定这是否正确)

&lt;Price&gt;k__BackingField 的一件事实际上是在 IL 中生成的支持字段的名称。 &lt;&gt; 在 C# 中不是标识符名称的有效部分,但是它们在 IL 中,这就是为什么在编译自动属性时它们会收到该名称,因此它不会与您可能创建的任何变量名称冲突你自己。自动属性只是编译器的魔法,毕竟它确实在后台创建了一个私有字段。

使用更完整的反编译器,您将获得更好的结果,例如,这是 DotPeek 在反编译时给出的结果(甚至在删除调试符号的情况下进行了优化):

  public class Product
  {
    public string Name { get; private set; }

    public Decimal Price { get; private set; }

    public static List<Product> GetSampleProducts()
    {
      return new List<Product>()
      {
        new Product()
        {
          Name = "ProductA",
          Price = new Decimal(1233, 0, 0, false, (byte) 2)
        },
        new Product()
        {
          Name = "ProductB",
          Price = new Decimal(1332, 0, 0, false, (byte) 2)
        },
        new Product()
        {
          Name = "ProductC",
          Price = new Decimal(2343, 0, 0, false, (byte) 2)
        },
        new Product()
        {
          Name = "ProductD",
          Price = new Decimal(2355, 0, 0, false, (byte) 2)
        }
      };
    }

    public override string ToString()
    {
      return string.Format("{0}: {1}", (object) this.Name, (object) this.Price);
    }
  }

【讨论】:

  • 顺便说一句,jetbrains.com/decompiler 可能是我见过的最好的 C# 反编译器,我相信他们可以正确处理这两种情况。 (无从属关系,只是他们产品的粉丝)
【解决方案2】:

最好的方法是让您获取该代码并尝试自己编译它以查看它是否是有效的 C# 代码。如果最终它确实是一个有效的 C# 代码,那么您应该阅读该代码并考虑它是否真的产生了相同的结果。

请记住,一旦代码被编译成IL,代码本身就会丢失,因此反编译器会尝试编写一个代码,它会为您提供与 IL 相同的结果...但编译器不可能总是给您原始代码的精确副本。

【讨论】:

    【解决方案3】:

    看起来反编译器对该列表的初始化感到困惑。它肯定没有生成有效的 C# 代码。看起来它试图制作列表中的项目然后添加它们,但它并不完全正确。总是很难反编译一些东西,所以我希望时不时地进行调整。

    您可以尝试编辑底部以明确添加 4 个新项目,并为它们命名。这可能会有所帮助。由于反编译器正在处理二进制文件,并最终由编译器控制它,因此有时对表达算法的方式稍作调整就会对其产生影响。

    【讨论】:

      【解决方案4】:

      “backingField”字段和属性有一半是正确的:{ get; private set; } 语法被编译为支持字段,以及执行简单赋值和访问的属性。 IL 会将支持字段列为具有无效名称,这很好。但是,属性应该包含 getter 和 setter 的内容(是的,由于字段名称无效,这将是语法错误,但它是 IL 的准确表示)。属性应该包含它们的编译体,或者处于{ get; private set; } 模式且不存在支持字段。同时拥有支持字段和{ get; private set; } 语法是不正确的。

      GetSampleProducts 的反编译代码肯定是不正确的......它不会在任何地方使用产品名称。我猜反编译器不处理对象初始化器语法。 (我不知道这是否是正确的名称。)

      原文:

      return new List<Product>()
      {
          new Product() { Name = "ProductA", Price = 12.33M },
          new Product() { Name = "ProductB", Price = 13.32M },
          new Product() { Name = "ProductC", Price = 23.43M },
          new Product() { Name = "ProductD", Price = 23.55M }
      };
      

      反编译:

      public static List<Product> GetSampleProducts()
      {
          List<Product> products = new List<Product>();
          Product num1.Price = new decimal(1233, 0, 0, false, 2).Add(num1);
          Product product1.Price = new decimal(1332, 0, 0, false, 2).Add(product1);
          Product num2.Price = new decimal(2343, 0, 0, false, 2).Add(num2);
          Product product2.Price = new decimal(2355, 0, 0, false, 2).Add(product2);
          return products;
      }
      

      应该是这样的:

      List<Product> products = new List<Product>();
      Product product1 = new Product();
      product1.Name = "ProductA";
      product1.Price = new decimal(1233, 0, 0, false, 2);
      products.Add(product1);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-05-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-04
        相关资源
        最近更新 更多