No i proszę, jak już coś wymyślę to się okazuje, że większość o tym wie :) Dużo kudos dla Pawła, oczywiście chodziło mi komendę:
ildasm TestBox.exe /text | findstr box
Jest to chyba najszybszy sposób uzyskania informacji o boxingu i unboxingu w kodzie, a staje się on jeszcze szybszy gdy zastosujemy rozszerzenie PowerCommands, wtedy wystarczy jedynie kliknąć na projekcie wybrać Open Command Prompt
i następnie przejść do katalogu bin/debug|release gdzie już możemy spokojnie operować na pliku – oczywiście dla chcących nie powinno być problemu wprowadzenie bin/debug/TestBox.exe zamiast przechodzić do katalogu.
Plus również dla FiDO, jednakże sparsowane tak wyniku zapytania by zwróciło nam zarówno tekst jak i linijkę nad nią/pod nią będzie już bardziej pracochłonne.
Myślałem, że padną także inne rozwiązania, a więc po krótce kilka słów o tych o których ja słyszałem.
nDepend
Posiadając nDepend jesteśmy wstanie dość szybko znaleźć metodę lub typ (i tylko i wyłącznie metodę lub typ), który zawiera w sobie boxing i/lub unboxing. Można to zrobić bardzo prostym zapytaniem:
Liczba linii to liczba linii w danej metodzie/w danym typie.
Mono.Cecil
Mono Cecil umożliwia nam odczytanie IL z skompilowanych już plików (jak i manipulację nim – wstawianie nowych komend, kasowanie istniejących itp) i w naszym przypadku wystarczy wykonać taki kod:
using System; using System.Linq; using Mono.Cecil; using Mono.Cecil.Cil; namespace TestBox { class Program { static void Main() { AssemblyDefinition ad = AssemblyDefinition.ReadAssembly( typeof(Program).Assembly.Location ); var instructions = from t in ad.MainModule.Types from m in t.Methods from i in m.Body.Instructions where i.OpCode == OpCodes.Box || i.OpCode == OpCodes.Unbox_Any || i.OpCode == OpCodes.Unbox select i; foreach(var instruction in instructions) { Console.WriteLine(instruction); } Console.ReadLine(); } } }
Jest to wersja uproszczona :) i wygląda prawie tak samo jak z ILDASM /text:
Możemy za to się pobawić trochę Cecil i na przykład wykorzystać dane z pliku PDB by pokazać także i plik źródłowy jak i linię wystąpienia błędu:
A tutaj kodzik to wykonujący:
using System; using System.Linq; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Cecil.Pdb; namespace TestBox { class Program { static void Main() { ISymbolReaderProvider readerProvider = new PdbReaderProvider(); ReaderParameters readerParameters = new ReaderParameters(ReadingMode.Immediate) { SymbolReaderProvider = readerProvider }; AssemblyDefinition ad = AssemblyDefinition.ReadAssembly( typeof(Program).Assembly.Location, readerParameters ); Action<Instruction> print = instr => { if(instr == null) return; if(instr.Previous == null) return; if(instr.Previous.SequencePoint == null) return; if(instr.Previous.SequencePoint.Document == null) return; Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("ttIL:t{0}", instr); Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("ttFile:t{0}", instr.Previous.SequencePoint.Document.Url); Console.WriteLine("ttLine:t{0}", instr.Previous.SequencePoint.StartLine); Console.WriteLine(); Console.ResetColor(); }; foreach(var typeDefinition in ad.MainModule.Types) { // for test purpose only, i'm loading my executable assembly // and i don't want to check if cecil code contains // boxing and unboxing if(!typeDefinition.Namespace.Contains("Boxing")) continue; foreach(var methodDefinition in typeDefinition.Methods) { var body = methodDefinition.Body; Console.WriteLine("{0}.{1}", typeDefinition.Namespace, typeDefinition.Name); Console.WriteLine("t" + methodDefinition.Name); var boxWhere = from i in body.Instructions where i.OpCode == OpCodes.Box select i; var unboxWhere = from i in body.Instructions where i.OpCode == OpCodes.Unbox_Any || i.OpCode == OpCodes.Unbox select i; foreach(var instruction in boxWhere) { print(instruction); } if(boxWhere.Count() == 0) { Console.ForegroundColor = ConsoleColor.White; Console.WriteLine("ttNo boxing..."); Console.ResetColor(); } foreach(var instruction in unboxWhere) { print(instruction); } if(unboxWhere.Count() == 0) { Console.ForegroundColor = ConsoleColor.White; Console.WriteLine("ttNo unboxing..."); Console.ResetColor(); } Console.WriteLine("{0}---------------{0}", Environment.NewLine); } } Console.ReadLine(); } } }
ILDASM/.NET Reflector
Do przejrzenia boxingu i unboxingu z poziomu UI, możemy wykorzystać .NET Reflector lub po raz kolejny ILDASM:
Podsumowanie
Czy są to wszystkie metody? Na pewno nie, ale są to te, które przychodzą mi na myśl. Można by się jeszcze pobawić CCI Metadata API, które też umożliwia wczytywanie plików PDB – tak naprawdę Cecil z niego korzysta.
Jeżeli znacie inne metody to podzielcie się nimi proszę :) dzięki