Is this valid C# code?
Is this valid C# code ?
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);
}
}
The example above is taken from JustDecompile ( a .NET decompiler ) you can see the original version below:
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.3开发者_高级运维2M },
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);
}
}
}
I want to know if the first listing is a decompiling error or if it is valid C# code, generated by the compiler. I am very curios what is with the code in the method GetSampleProducts.
It's pretty simple to see that it's not valid C# code by pasting it into a compiler and trying to compile it.
It seems like the decompiler doesn't know how to properly handle auto-properties and the object literal syntax (not sure if that's the proper term)
One thing with <Price>k__BackingField
that is actually the name of the backing field generated in IL. <
and >
aren't valid parts of an identifier name in C# however they are in IL which is why they receive that name when auto-properties are compiled, so it doesn't conflict with any variable names you might create yourself. Auto-properties are just compiler magic that actually does create a private field in the background after all.
With a more complete decompiler you'll get better results, for example, this is what DotPeek gives when decompiling (even optimized with debugging symbols removed):
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);
}
}
The best way would be for you to take that code and try and compile it yourself to see if it's a valid C# code. If, at the end, it indeed is a valid C# code then you should read the code and think if it actually produces the same result.
Remember that once the code is compiled into IL, the code itself's lost and so the decompiler attempts to write a code that gives you the same result as the IL... but it's impossible for the compiler to always give you an exact copy of the original code.
It looks like that decompiler got confused by the initialization of that list. It definitely did not generate valid C# code. It looks like its trying to make the items of the list and then add them, but it didn't quite get it right. Its always hard to decompile something, so I would expect to have to make tweaks every now and then.
You could try editing the bottom section to explicitly add 4 new items, and give them names. That will probably help. Since the decompiler is working off the binary, and ultimately the compiler controls it, sometimes slight tweaks in how you express your algorithms can effect it.
The "backingField" fields & properties are half-correct: The { get; private set; }
syntax gets compiled as a backing field, and properties that do a simple assignment & access. The IL will list the backing field as having an invalid name, and that's fine. However, the properties should have included the contents of the getter & setter (which yes, would be a syntax error because of the invalid field name, but it is an accurate representation of the IL). The properties should have either included their compiled bodies, or be in { get; private set; }
mode with the backing fields not present. Having both the backing field and the { get; private set; }
syntax is not correct.
The decompiled code for GetSampleProducts certainly isn't correct... It doesn't use the product name anywhere. I'm guessing that the decompiler doesn't handle the object initializer syntax. (I don't know if that's the proper name.)
Original:
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 }
};
Decompiled:
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;
}
Should be something like this:
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);
精彩评论