MSDN > 論壇首頁 > Phoenix > How to add and reference a new field within Generic Class
發問發問
 

問題How to add and reference a new field within Generic Class

  • 2009年6月25日 下午 09:35AAyoub 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     包含代碼

    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!

     


所有回覆

  • 2009年6月26日 下午 04:46AAyoub 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     包含代碼

    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.

  • 2009年7月4日 上午 02:29AAyoub 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     包含代碼

    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;
    }
    
    • 已標示為解答AAyoub 2009年7月4日 上午 02:33
    • 已編輯AAyoub 2009年7月4日 上午 02:33
    • 已取消標示為解答AAyoub 2009年7月4日 上午 02:34
    •