2015-03-31 14 views
6

Używam Mono.Cecil do przepisywania niektórych zespołów. Biorąc pod uwagę ogólną klasę z polem łańcuchowym na przykład. Chcę wygenerować kod do metody tej klasy, która zapisuje w tym polu. Jest to kod, aby to osiągnąć:Jak zapisać wartość do ogólnego pola klasy (Mono.Cecil)

var origInstanceField = type.Fields.First(fld => fld.Name.Equals("_original")); 
InsertBeforeReturn(instanceMethod.Body, new[] 
{ 
    Instruction.Create(OpCodes.Ldarg_0), 
    Instruction.Create(OpCodes.Ldstr, "genCodeToOriginal"), 
    Instruction.Create(OpCodes.Stfld, origInstanceField) 
}); 

Dla klas nierodzajową działa jak czar. Dla klas ogólnych tworzy złe IL. Jeśli spojrzysz na zdekompilowaną IL, możesz zauważyć różnicę w porównaniu z tymi samymi instrukcjami wysyłanymi przez kompilator.

.method public hidebysig instance void FillFields() cil managed 
{ 
.maxstack 8 
L_0000: nop 
L_0001: ldarg.0 
L_0002: ldstr "non-gen code to non-gen field" 
L_0007: stfld string TestConsole.GenericClass`1<!T>::_original 
L_0017: ldarg.0 
L_0018: ldstr "genCodeToOriginal" 
L_001d: stfld string TestConsole.GenericClass`1::_original 
L_0022: ret 
} 

Punkty odniesienia pola do typu otwartego generycznej [GenericClass <>] a nie do być zbudowany Typ [GenericClass < T>]. Próbowałem również ze statycznym polem z tym samym wynikiem.
Każdy pomysł, w jaki sposób mogę uzyskać właściwą definicję FieldDefinition?

+0

Dlaczego nie używasz tylko odbicia? – Servy

+0

Co to jest "typ"? Nie może to być 'TypeBuilder', ponieważ nie ma właściwości' Fields'. – svick

+0

Odbicie może być w porządku, ale w moim przypadku stworzę również pole z Cecilem, więc nie ma refleksji. Typ zmiennej to TypeDefinition. – csnemes

Odpowiedz

4

Udało mi się znaleźć rozwiązanie, sprawdzając kod źródłowy programu Anotar (https://github.com/Fody/Anotar). Sztuką jest stworzenie odniesienia do pola z definicją typu odnoszącą się do instancji generycznej, a nie oryginalnej.

var declaringType = new GenericInstanceType(definition.DeclaringType); 
foreach (var parameter in definition.DeclaringType.GenericParameters) 
{ 
    declaringType.GenericArguments.Add(parameter); 
} 
return new FieldReference(definition.Name, definition.FieldType, declaringType); 

Użycie tej transformacji w definicji pola pochodzącej z typu daje prawo FieldReference. Podawanie ogólnych parametrów do ogólnych argumentów jest trochę dziwne, ale ma sens.

+0

Naprawdę działa jak urok! –

Powiązane problemy