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# コードではないことを確認するのは非常に簡単です。

逆コンパイラは、自動プロパティとオブジェクト リテラル構文を適切に処理する方法を認識していないようです (それが適切な用語かどうかはわかりません)。

その 1 つ<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

「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 に答える
0

最善の方法は、そのコードを取得して自分でコンパイルして、有効な C# コードかどうかを確認することです。最後に、それが実際に有効な C# コードである場合は、コードを読んで、実際に同じ結果が生成されるかどうかを検討する必要があります。

コードがILにコンパイルされると、コード自体が失われるため、逆コンパイラは IL と同じ結果をもたらすコードを記述しようとしますが、コンパイラが常に正確なコピーを提供することは不可能です。オリジナルコード。

于 2011-08-03T20:27:19.810 に答える
0

その逆コンパイラは、そのリストの初期化によって混乱したようです。有効な C# コードが生成されなかったことは間違いありません。リストの項目を作成してから追加しようとしているように見えますが、うまくいきませんでした。何かを逆コンパイルするのは常に難しいので、時々微調整する必要があると思います。

一番下のセクションを編集して、4 つの新しい項目を明示的に追加し、それらに名前を付けることができます。それはおそらく役立つでしょう。逆コンパイラはバイナリを処理し、最終的にはコンパイラがそれを制御するため、アルゴリズムの表現方法を少し調整すると、バイナリに影響を与えることがあります。

于 2011-08-03T20:28:07.750 に答える