2011-09-16 4 views
2

В версиях ColdFusion до 8 дублирующаяся функция генерирует ошибку, если в структуре есть какие-либо компоненты. В 8 и выше он будет работать, но при копировании компонентов возникают проблемы.Как глубоко копировать (клонировать) структуру при игнорировании компонентов

Итак, мне нужен способ создания глубокой копии структуры, которая игнорирует компоненты. Для моих целей это для отладки, мне нужен снимок области переменных в определенной точке кода, поэтому эффективность не имеет большого значения, поскольку это никогда не выйдет из среды разработки. В настоящее время с использованием CF 7 я бы взял 8 предложений, если бы только решить эту проблему, но я не контролирую апгрейд :(

ответ

5

Пока вы не убивали клетки мозга, я принял удар по рекурсивной функции;) Он исключает компоненты и объекты java/com. Ни один из которых MX7 не может дублировать. Я бросил функции в компонент, чтобы избежать вмешательства в область variables. Затем сохраните экземпляр в области request.

Не проверено строго. Поэтому я уверен, что есть возможности для улучшения.

Использование

<cfset request.util = createObject("component", "Util")> 
<cfset request.copy = request.util.duplicateStructMinusObjects(variables)> 
<cfdump var="#request.copy#"> 

Util.cfc

<cfcomponent> 
    <cfscript> 
      function duplicateArrayMinusObjects(input) { 
        var x  = ""; 
        var value = ""; 
        var output = arrayNew(1); 

        for (x = 1; x lte arrayLen(arguments.input); x = x + 1) { 
          value = arguments.input[x]; 

          // note components are considered structures 
          if (IsStruct(value) and not IsObject(value)) { 
            arrayAppend(output, duplicateStructMinusObjects(value)); 
          } 
          else if (IsArray(value)) { 
            arrayAppend(output, duplicateArrayMinusObjects(value));     
          } 
          else if (not IsObject(value)){   
            arrayAppend(output, duplicate(value)); 
          } 
        }   
        return output; 
      } 

      function duplicateStructMinusObjects(input) { 
        var key = ""; 
        var value = ""; 
        var output = structNew(); 

        for (key in arguments.input) { 
          value = arguments.input[key]; 

          // note components are considered structures 
          if (IsStruct(value) and not IsObject(value)) { 
            output[key] = duplicateStructMinusObjects(value); 
          } 
          else if (IsArray(value)) { 
            output[key] = duplicateArrayMinusObjects(value); 
          } 
          else if (not IsObject(value)){   
            output[key] = duplicate(value); 
          } 
        } 

        return output; 
      } 
    </cfscript> 
</cfcomponent> 
+0

Я думал об этом подходе, когда-то читал вопрос в RSS :) – Sergii

+0

Великие умы;) (Это случилось со мной на нескольких ваших ответах). Конечный результат был немного проще, чем я думал. Благодарим за рекурсию. – Leigh

+1

Взгляните на шаблон оформления Memento - когда вы нажмете объект, я склоняюсь к вызову Memento и получаю его, чтобы возвращать как структуру все свойства этого объекта в его текущем состоянии.Был отличным способом отладки таких вещей, как состояние сеанса, и означал, что я не сбрасывал физические объекты. –

1

Неважно, как долго вы думаете/ищете, вы всегда придумываете ответ сразу после того, как вы зададите вопрос.

Я смог решить это путем преднамеренного неправильного использования try/catch, поэтому я зациклился на структуре, попытался создать объект из каждого элемента, как если бы он был компонент и ошибка, скопировали его в мою структуру моментальных снимков. Мне также пришлось хранить его в другой области, в моем случае я использовал сеанс, так как если бы я позволил ему перейти к переменным по умолчанию, была бы круговая ссылка, которая вызывает структура с бесконечным числом детей.

EDIT: Это не то, что я думал, что это DID, СМОТРИТЕ НИЖЕ

<cfset session.varSnapShot = StructNew()> 
<cfset loopList = StructKeyList(variables)> 
<cfloop from="1" to="#ListLen(loopList)#" index="i"> 
    <cftry> 
     <cfobject name="x#i#" component="#variables[ListGetAt(loopList,i)]#"> 
     <cfcatch> 
      <cfset session.varSnapShot[ListGetAt(loopList,i)]= variables[ListGetAt(loopList,i)]> 
     </cfcatch> 
    </cftry> 
</cfloop> 

EDIT: Так как выше на самом деле не делать глубокую копию (спасибо Leigh) Я пришел с этим:

<cfloop from="1" to="#ListLen(loopList)#" index="i"> 
    <cfset metaData = GetMetaData(variables[ListGetAt(loopList,i)])> 
    <cfif isStruct(metaData) AND isDefined("metaData.type") AND metaData.type EQ "component"> 
    <cfelse> 
     <cfset session.varSnapShot[ListGetAt(loopList,i)]= duplicate(variables[ListGetAt(loopList,i)])> 
    </cfif> 
</cfloop> 

Это делает глубокую копию, но все равно будет проблемой, если компонент находится ниже первого уровня объекта. Я хотел создать рекурсивный метод, но через полтора часа он уходит в пятницу. Вместо этого я буду убивать клетки мозга в пабе и, возможно, обновить это с помощью рекурсивного метода в понедельник, если не забуду.

+1

Я думаю, что вы забыли 'duplicate';) Я подозреваю, что это сложнее, чем это. Если какие-либо компоненты находятся во вложенном объекте, вы вернетесь к квадрату. Вам понадобится рекурсивная функция. – Leigh

+0

хорошая точка, на этом этапе у меня есть объект ссылок, поэтому у меня есть только переменные, которые у меня есть, но не обязательно одинаковые значения. Рекурсия тоже обязательна. Я постараюсь реорганизовать, если кому-то понадобится что-то подобное. – invertedSpear