Search Unity

Code Inject. Property Injection.

Discussion in 'Scripting' started by techmage, Dec 22, 2014.

  1. techmage

    techmage

    Joined:
    Oct 31, 2009
    Posts:
    2,133
    So I am trying to write a code injection class through Mono.Cecil so that you can do things like put [TransformCache] attribute on a class and have it inject the getter setter for that. I know in Unity 5 that transform cacheing is to be less needed, but this type of functionality would still be useful for a lot of things I think. I am having trouble figuring out all the specifics of the poorly document Cecil. Here is how far I have gotten, anyone want to help me figure this out and think about this?

    This class is where you list out the attributes that will be injectable in the InjectAttribute class. Then you put your methods, properties or fields, named the same, into the Inject Method class.

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class InjectMethod : MonoBehaviour
    4. {
    5.     public Transform TransformCache
    6.     {
    7.         get
    8.         {
    9.             if (transformCache == null)
    10.                 transformCache = this.GetComponent<Transform>();
    11.             return transformCache;
    12.         }
    13.     }
    14.     private Transform transformCache;
    15.  
    16. }
    17.  
    18. public class InjectAttribute
    19. {
    20.     public class TransformCache : System.Attribute
    21.     {    
    22.     }
    23.    
    24.     public class InjectFlag : System.Attribute
    25.     {    
    26.     }
    27. }    

    This is CecilInject.cs
    This class will scan through all modules, types, vars. If it finds an attribute that is of the same name as an attribute in InjectAttribute, it will inject the same named Method, Property or Field in InjectMethod class. Or thats what it should do. It does't do that yet. I can't figure it out.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. using Mono.Cecil;
    6. using Mono.Cecil.Cil;
    7.  
    8.  
    9. [InitializeOnLoad]
    10. static class AssemblyPostProcessor
    11. {
    12.     static AssemblyPostProcessor()
    13.     {
    14.         var assembly = AssemblyDefinition.ReadAssembly(Application.dataPath+"/../Library/ScriptAssemblies/Assembly-CSharp.dll");
    15.        
    16.         foreach (var attribute in assembly.CustomAttributes)
    17.         {
    18.             if (attribute.AttributeType.Name == "InjectFlag")
    19.             {
    20.                 Debug.Log("Already injected, aborting");
    21.                 return;
    22.             }
    23.         }            
    24.        
    25.         List<string> attributeList = new List<string>();
    26.        
    27.         foreach (var module in assembly.Modules)
    28.         {            
    29.             foreach (var type in module.Types)
    30.             {                
    31.                 if (type.HasMethods && type.Name == "InjectAttribute")
    32.                 {                                                    
    33.                     foreach (var nestedType in type.NestedTypes)
    34.                     {        
    35.                         attributeList.Add( nestedType.Name.Replace("InjectAttribute/","").ToLower() );
    36.                     }
    37.                 }
    38.             }    
    39.         }
    40.        
    41.         foreach (var module in assembly.Modules)
    42.         {            
    43.             foreach (var type in module.Types)
    44.             {                
    45.                 if (type.HasMethods && type.Name == "InjectMethod")
    46.                 {
    47.                     foreach (var method in type.Methods)
    48.                     {
    49.                         if (attributeList.Contains( method.Name.ToLower() ))
    50.                         {
    51.                             Debug.Log("Method: "+method.Name);
    52.                                                    
    53.                         }
    54.                     }    
    55.                    
    56.                     foreach (var property in type.Properties)
    57.                     {        
    58.                         if (attributeList.Contains( property.Name.ToLower() ))
    59.                         {
    60.                             Debug.Log("Property: "+property.Name);
    61. //                            type.Properties.Add
    62.                                                    
    63.                         }
    64.                     }
    65.                    
    66.                     foreach (var field in type.Fields)
    67.                     {        
    68.                         if (attributeList.Contains( field.Name.ToLower() ))
    69.                         {
    70.                             Debug.Log("Field: "+field.Name);
    71.                                    
    72.                         }
    73.                     }                    
    74.                 }
    75.             }    
    76.         }        
    77.        
    78.         var attribDefaultCtorRef = assembly.MainModule.Import(typeof(InjectAttribute.InjectFlag).GetConstructor( System.Type.EmptyTypes ) );
    79.         var attrib = new CustomAttribute(attribDefaultCtorRef);    
    80.         assembly.CustomAttributes.Add(attrib );
    81.        
    82.         assembly.Write(Application.dataPath+"/../Library/ScriptAssemblies/Assembly-CSharp.dll");                        
    83.     }
    84.    
    85.    
    86.     private static bool HasAttribute(string attributeName, IEnumerable<CustomAttribute> customAttributes)
    87.     {
    88.         return GetAttributeByName(attributeName, customAttributes) != null;
    89.     }
    90.  
    91.     private static CustomAttribute GetAttributeByName(string attributeName, IEnumerable<CustomAttribute> customAttributes)
    92.     {
    93.         foreach (var attribute in customAttributes)
    94.             if (attribute.AttributeType.FullName == attributeName)
    95.                 return attribute;
    96.         return null;
    97.     }    
    98.        
    99. }
    Anyone know some about this?