Search Unity

Reflection : casting array-objects into its original type

Discussion in 'Scripting' started by DrKucho, Jul 23, 2017.

  1. DrKucho

    DrKucho

    Joined:
    Oct 14, 2013
    Posts:
    140
    I am writing an editor script to copy all visible value types (and not references) of all components of a gameObject using reflection, it works mostly but when it comes to arrays I have problems:

    an array is also marked as class in reflection's fieldInfo, but if you try to GetFields() it will return 0, that's why this code won't copy any array, I can copy the whole array same way I do for valueTypes , but then if the array has references to GameObjects or Components it will copy them and i need to ignore them.

    Code (CSharp):
    1.  
    2.  using UnityEngine;
    3. using System.Reflection;
    4. using UnityEditor;
    5.  
    6. [ExecuteInEditMode]
    7. public class CopyAllValuesNoReferences : MonoBehaviour {
    8.        
    9.  
    10.     static public GameObject src;
    11.     static public GameObject dst;
    12.  
    13.     static public int securityCount;
    14.  
    15.     [MenuItem("Tools/Copy Components Values")]
    16.     public static void CopyComponentsValues(){
    17.         src = Selection.activeGameObject;
    18.     }
    19.  
    20.     [MenuItem("Tools/Paste Component Values")]
    21.     public static void PasteComponentValues(){
    22.         securityCount = 0;
    23.         dst = Selection.activeGameObject;
    24.         // pillo todos los componentes
    25.         Component[] srcComps = src.GetComponents<Component>();
    26.         Component[] dstComps = dst.GetComponents<Component>();
    27.         foreach (Component srcComp in srcComps)
    28.         {
    29.             if (srcComp.GetType() != typeof(Transform))
    30.             {
    31.                 System.Type t = srcComp.GetType();
    32.                 // pillo solo los componentes de tipo especifico
    33.                 Component[] typeSrcComps = src.GetComponents(t);
    34.                 Component[] typeDstComps = dst.GetComponents(t);
    35.  
    36.                 if (typeSrcComps != null && typeDstComps != null && typeSrcComps.Length == typeDstComps.Length)
    37.                 {
    38.                     for (int i = 0; i < typeSrcComps.Length; i++)
    39.                     {
    40.                         CopyAllValueFieldsRecursivelly(typeSrcComps[i], typeDstComps[i]);
    41.                     }
    42.                 }
    43.             }
    44.         }
    45.     }
    46.     public static void CopyAllValueFieldsRecursivelly(object src, object dst){
    47.         if (src != null && dst != null)
    48.         {
    49.             System.Type srcType = src.GetType();
    50.             System.Type dstType = src.GetType();
    51.             if (srcType == dstType)
    52.             {
    53.                 FieldInfo[] fields = srcType.GetFields();
    54.                 foreach (FieldInfo field in fields)
    55.                 {
    56.                     if (field.IsPublic)    
    57.                     {
    58.                         var hide = field.GetCustomAttributes(typeof(HideInInspector), false);
    59.                         if (hide.Length == 0) // no esta oculto en inspector
    60.                         {
    61.                             System.Type fieldType = field.FieldType;
    62.                             if (fieldType.IsValueType)
    63.                             {
    64.                                 object value = field.GetValue(src);
    65.                                 field.SetValue(dst, value);
    66.                             }
    67.                             else if (fieldType.IsClass)
    68.                             {
    69.                                 if (securityCount < 1000)
    70.                                 {
    71.                                     object srcClass = field.GetValue(src);
    72.                                     Component isComponent = null;
    73.                                     try
    74.                                     {
    75.                                         isComponent = (Component)srcClass;
    76.                                     }
    77.                                     catch{}
    78.  
    79.                                     if (isComponent == null) // no es una referencia
    80.                                     {
    81.                                         print("COPIANDO " + field.Name);
    82.                                         object dstClass = field.GetValue(dst);
    83.                                         if (srcClass == null || dstClass == null)
    84.                                             print("FIELD " + field.Name + " ES NULL");
    85.                                         else
    86.                                             CopyAllValueFieldsRecursivelly(srcClass, dstClass);
    87.                                     }
    88.                                     else
    89.                                     {
    90.                                         print("NO COPIO " + field.Name + " (REFERENCIA COMP)");
    91.                                     }
    92.                                     securityCount++;
    93.                                 }
    94.                             }
    95.                         }
    96.                     }
    97.                 }
    98.             }
    99.         }
    100.         else
    101.         {
    102.             print(" FUENTE O DESTINO SON NULL? WTF!");
    103.         }
    104.     }
    105. }
    106.  


    I thought about iterating array elements and process them one by one but I can't cause the array comes as an "object" and I don't know how to cast an object to its original type in the case we don't know which type was it, yes I can get the type of the object with GetType()

    System.Type myType = arrayObject.GetType();

    but I can't do :

    var castedArray = (myType) arrayObject;

    or

    var castedArray = arrayObject as myType;

    I tried to iterate the arrayObject directly with:

    foreach(object obj in arrayObject)

    But get an error cause objects are not IENumerable. :(