How to add and reference a new field within Generic Class
Hi,
I’m working with Phoenix for .Net Assembly Transformation and my question is how we can add a new field to a generic Class and then load it.
Suppose for instance we have the following Generic Class :
public class Test<T> { private T value; public Test(T value) { this.value = value; } public T Value { get { return value; } set { this.value = value; } } }
And we need to transform this to
public class Test<T> { private T value; int newfield; public Test(T value) { this.value = value; } public T Value { get { return value; } set { this.value = value; } } public void MyMethod(int t) { newfield = t; } }
When I consider the field as a usual field, I’m able to generate the modified generic class. However the PEVerify tool complain with the following Error :
System.BadImageFormatException: Fields inside generic classes must be referenced using MemberRefs, even in the same module as the class.
After some try I noted that to reference a field within the generic class we have to load the field of the class instantiated with the type variable “!0” as follows :
Phx.Collections.TypeList typeList = Phx.Collections.TypeList.New(Phx.GlobalData.GlobalLifetime); typeList.Append(testType.TypeVariableTypeList.Head.Data); Phx.Types.AggregateType insta = testType.Instantiate(typeList);However this works only for an existing field because when we add a new field to the generic class, this field does not appear in the instantiated class. Even, if I try to add the field manually I get exception error.
Can somebody give me a guidance please?
Thank you!
Все ответы
Hi,
Here a workaround for the previous question. To load a field, I use the following Function:
public Phx.IR.ValueInstruction ldfld(Phx.Symbols.FieldSymbol fieldsymbol, bool append) { Phx.IR.ValueInstruction inst = Phx.IR.ValueInstruction.NewUnary(funit, Phx.Targets.Architectures.Msil.Opcode.ldfld, stackslot, Phx.IR.MemoryOperand.New(funit, fieldsymbol.Field, null, stackslot, 0, Phx.Alignment.NaturalAlignment(fieldsymbol.Type), funit.AliasInfo.AllHeapMemoryTag, funit.SafetyInfo.SafeTag)); funit.Legalize.Instruction(inst); if (fieldsymbol.EnclosingAggregateType.IsGeneric) { Phx.Collections.TypeList typeList = Phx.Collections.TypeList.New(Phx.GlobalData.GlobalLifetime); foreach (Phx.Types.TypeVariableType typeVar in fieldsymbol.EnclosingAggregateType.TypeVariableTypeList) { typeList.Append(typeVar); } Phx.Types.AggregateType instance = fieldsymbol.EnclosingAggregateType.Instantiate(typeList); Phx.Symbols.FieldSymbol thisfield = instance.FieldSymbolList; while (thisfield != null) { if (thisfield.UninstantiatedFieldSymbol == fieldsymbol) { thisfield.IsToolGenerated = false; thisfield.NeedsFixup = true; thisfield.MustBeEmittedInMetadata = true; inst.SourceOperand.ResetField(thisfield.Field); break; } thisfield = thisfield.NextFieldSymbol; } } if (append) appendInst.InsertBefore(inst); return inst; }
When the field is newly added, we have to create the memory operand before; elsewhere the field is not populated in the FieldSymbolList of the instantiated class.
A better and more general solution for this problem will be appreciated.
Hi,
The following code shows how we can obtain a generic class function symbol newly created to do a call from another function of the same generic class. We have to create a function symbol with a visibility ClrTokenReference and append it to the instantiated class.
public Phx.Symbols.FunctionSymbol ResetFunction(Phx.Symbols.FunctionSymbol funcsymbol) { if (funcsymbol.EnclosingAggregateType.IsGeneric) { Phx.Collections.TypeList typeList = Phx.Collections.TypeList.New(Phx.GlobalData.GlobalLifetime); foreach (Phx.Types.TypeVariableType typeVar in funcsymbol.EnclosingAggregateType.TypeVariableTypeList) { typeList.Append(typeVar); } Phx.Types.AggregateType instance = funcsymbol.EnclosingAggregateType.Instantiate(typeList); Phx.Symbols.FunctionSymbol thisfunction = Phx.Symbols.FunctionSymbol.New(moduleUnit.SymbolTable, 0, funcsymbol.Name, funcsymbol.FunctionType, Phx.Symbols.Visibility.ClrTokenReference); instance.AppendMethodSymbol(thisfunction); instance.TypeSymbol.InsertInLexicalScope(thisfunction, thisfunction.Name); thisfunction.MustBeEmittedInMetadata = true; thisfunction.UninstantiatedFunctionSymbol = funcsymbol; return thisfunction; } else return funcsymbol; }

