C# - Fordítási hibák lekérdezése

Fordító alkalmazás C#-ban 2. rész

forráskód letöltése
A cikksorozat előző részében egy szöveg formájában megadott forráskódot fordítottunk le, és generáltunk futtatható állományt programból. Ebben a cikkben azt vizsgáljuk meg, hogy egy fizikai C# állományban elhelyezett forráskódot milyen módszerekkel fordítunk le, és az esetlegesen megjelenő fordítási hibákat hogyan kérdezhetjük le, azokról milyen jellegű információkat kaphatunk.
Az alkalmazásban egy OpenFileDialog komponens segítségével kereshetünk olyan állományokat, melyek .CS kiterjesztésűek, és forráskódot tartalmaznak. A példa kedvéért az alkalmazás mappájának cs_src alkönyvtárában elhelyeztünk egy SourceSample.cs nevű forrásállományt, melynek a 10. sorában egy karakterlánc deklarációt szándékosan elírtunk, modellezendő a fordítási hibák létrejöttét. Ez láncolt módon további hibák előfordulását, így hiba jelzések megjelenését vonja maga után a fordítás folyamatában, meghiúsítva a futtatható állomány generálását.
A fordító metódus meghívása után a felületen elhelyezett DataGrid kontrolban jelennek meg a fordítási hibák adatai, valamint felbukkan egy, a forráskódot tartalmazó űrlap objektum is.
A fordításhoz, akár csak a múlt részben, deklarálunk egy objektumot a Microsoft.CSharp névtér CSharpCodeProvider osztályából:
private void buildButton_Click(object sender, System.EventArgs e)
{
  ...
  CSharpCodeProvider codeProvider = new CSharpCodeProvider();
Az osztály CreateCompiler metódusával létrehozhatunk egy ICompiler interfészt, melynek metódusait és property-jeit használhatjuk fel a fordításhoz. Ez implementálja a fordító motort:
  ICodeCompiler compiler = codeProvider.CreateCompiler();
Létrehozunk egy objektumot a paraméterek számára:
  CompilerParameters parameters = new CompilerParameters();
Jelezzük, hogy futtatható kód elkészítésére van szükségünk (természetesen osztály könyvtárat tartalmazó állományok esetén ez a property FALSE értékű):
  parameters.GenerateExecutable = true;
Megadjuk a futtatható állomány nevét, a fő osztály nevét, valamint jelezzük, hogy DEBUG, vagy RELEASE alkalmazást fordítunk, illetve begyűjtjük a hivatkozott Assembly objektumokat:
  parameters.OutputAssembly = nameText.Text;
  parameters.MainClass = "MyApplication.FileCopier";
  parameters.IncludeDebugInformation = includeDebug.Checked;
  foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) 
  {
    parameters.ReferencedAssemblies.Add(asm.Location);
  }
A fordító motort reprezentáló objektum CompileAssemblyFromFile metódusát használjuk fel ahhoz, hogy az állományokban megadott forráskódokat fordítsuk. Ennek átadjuk a paraméterlistát tartalmazó objektumot, valamint a megadott állomány nevét teljes elérési úttal:
  CompilerResults results = compiler.CompileAssemblyFromFile(parameters,pathText.Text);
A metódus visszatérési értéke egy CompilerResults objektum, mely Errors property-jében, egy listában tartalmazza a fordításkor keletkező hibákat. Ezek CompilerErrors osztályú objektumok, melyek property-jeit lekérdezve hasznos információkat szerezhetünk a keletkezés helyéről, illetve minőségéről. A példában ellenőrizzük, hogy az Errors lista mennyi elemet tartalmaz a fordítási művelet végrehajtása után. Ha ez az érték nem nulla, akkor megjelenítjük a hibákat egy DataGrid-ben, a forrás DataTable objektum egyes oszlopainak értékül adva a szerzett információkat:
  if (results.Errors.Count > 0)      
  {
Az oszlopdefiníciók létrehozása után egy ciklussal kiírjuk a rekordokba a keletkezett hiba adatokat. Az első oszlopba kerül a hiba minőségére utaló szócska (Warning, illetve Error) attól függően, hogy az egyes hibaobjektumok IsWarning property-je TRUE, vagy FALSE értékű:
    foreach (CompilerError err in results.Errors) 
    {
      dr = dt.NewRow();
      if (err.IsWarning)
      {
        dr[0] = "Warning";
      }
      else
      {
        dr[0] = "Error";
      }
A következő oszlopba kerül a hiba száma az ErrroNumber property kiolvasásával:
      dr[1] = err.ErrorNumber;
Ezt követi a hiba szövege az ErrorText property-ből:
      dr[2] = err.ErrorText;
A hibás sor száma a Line property-ből:
      dr[3] = err.Line.ToString();
Illetve az oszlopszám a Column property-ből:
      dr[4] = err.Column.ToString();
      ...
    }
    ...
  }
  ...
}
Az alkalmazásban megjelenítünk egy másik űrlapot is a forráskóddal, hogy szemléltessük a hibák helyét. A létrehozáskor a Form2 osztály konstruktorának átadunk paraméterként két értéket, melyek alapján megjeleníti a forráskódot egy ListBox kontrolban, és a hibás sorok számát egy ComboBox kontrolban. A paraméterek ArrayList objektumok, source, illetve rows névvel.
A rows listába bekerülnek a sorszámok, míg a a source lista elemeit egy StringBuilder objektum adatai alapján állítjuk össze, mely a forráskódot tartalmazza karakterlánc formájában.
A kijavított és lefordított alkalmazást a Process osztály Start metódusával futtathatjuk, a létrehozott ProcessInfo osztályból példányosított objektumot átadva paraméterként.

ProcessStartInfo pInfo = new ProcessStartInfo(nameText.Text);
Process.Start(pInfo);
A mellékelt forráskód egy konzol alkalmazást tartalmaz, mely parancssori argumentumként kap egy fájlnevet elérési útvonallal, melyet töröl, ha az létezik. Amennyiben ilyen argumentumot nem adunk át indításkor, akkor indulás után is megadhatjuk. Létező állomány megadásakor az törlődik az ENTER lenyomása után.

Fordító alkalmazás C#-ban cikksorozat

Forráskód fordítása és futtatható állomány generálása - Fordító alkalmazás C#-ban 1. rész

Fordítási hibák lekérdezése - Fordító alkalmazás C#-ban 2. rész