这是有效的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 中的代码是什么。
答案 0 :(得分: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);
}
}
答案 1 :(得分:0)
最好的方法是让你获取代码并尝试自己编译,看看它是否是一个有效的C#代码。如果最后它确实是一个有效的C#代码,那么你应该阅读代码并思考它是否实际产生相同的结果。
请记住,一旦代码编译成IL,代码本身就会丢失,因此反编译器会尝试编写一个代码,使您获得与IL相同的结果......但编译器不可能始终给你一份原始代码的精确副本。
答案 2 :(得分:0)
看起来反编译器因该列表的初始化而感到困惑。它肯定没有生成有效的C#代码。看起来它试图制作列表中的项目然后添加它们,但它并没有完全正确。它总是很难反编译,所以我不得不经常做出调整。
您可以尝试编辑底部以明确添加4个新项目,并为其命名。这可能会有所帮助。由于反编译器正在处理二进制文件,并且最终编译器对其进行控制,因此有时对表达算法的方式进行微调会影响它。
答案 3 :(得分:0)
“backingField”字段&amp;属性是半正确的:{ get; private set; }
语法被编译为支持字段,以及执行简单赋值的属性&amp;访问。 IL会将支持字段列为具有无效名称,这没关系。但是,这些属性应该包括吸气剂和吸气剂的内容。 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);