Это действительный код C #? - PullRequest
1 голос
/ 04 августа 2011

Это действительный код 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 ]

5 голосов
/ 04 августа 2011

Довольно просто увидеть, что это недопустимый код 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);
    }
  }
0 голосов
/ 04 августа 2011

Поля и свойства "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);
0 голосов
/ 04 августа 2011

Похоже, что декомпилятор запутался из-за инициализации этого списка. Это определенно не генерирует действительный код C #. Похоже, он пытается создать элементы списка, а затем добавить их, но это не совсем правильно. Всегда сложно что-то декомпилировать, поэтому я ожидал бы время от времени вносить изменения.

Вы можете попробовать отредактировать нижний раздел, чтобы явно добавить 4 новых элемента и дать им имена. Это, вероятно, поможет. Поскольку декомпилятор работает с двоичным файлом, и, в конечном счете, компилятор управляет им, иногда небольшие изменения в том, как вы выражаете свои алгоритмы, могут повлиять на это.

0 голосов
/ 04 августа 2011

Лучшим способом было бы, чтобы вы взяли этот код и попытались скомпилировать его самостоятельно, чтобы проверить, является ли он допустимым кодом C #.Если, в конце концов, это действительно допустимый код C #, вам следует прочитать код и подумать, действительно ли он дает тот же результат.

Помните, что как только код скомпилирован в IL сам код потерян, и поэтому декомпилятор пытается написать код, который дает тот же результат, что и IL ... но компилятор не может всегда дать вам точную копию исходного кода.

...