1

这是有效的 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方法中的代码是什么。

4

4 回答 4

5

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

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

其中一件事<Price>k__BackingField实际上是在 IL 中生成的支持字段的名称。 <并且>不是 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);
    }
  }
于 2011-08-03T20:26:52.237 回答
0

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

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

于 2011-08-03T20:27:19.810 回答
0

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

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

于 2011-08-03T20:28:07.750 回答
0

“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);
于 2011-08-03T20:35:21.610 回答