Как динамически создать экземпляр класса и установить свойство во время выполнения во Flex 3? - PullRequest
2 голосов
/ 17 февраля 2010

Используя org.as3commons.reflect, я могу найти имя класса и создать экземпляр класса во время выполнения. У меня также есть (нерабочий) код, который вызывает метод. Тем не менее, я действительно хочу установить значение свойства. Я не уверен, реализованы ли свойства как методы внутри Flex.

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


package com.acme.reporting.builders
{
 import com.acme.reporting.model.Metadata;

 import mx.core.UIComponent;

 import org.as3commons.reflect.ClassUtils;
 import org.as3commons.reflect.MethodInvoker;

 public class UIComponentBuilder implements IUIComponentBuilder
 {
  public function build(metadata:Array):UIComponent
  {
   var typeClass:Class = ClassUtils.forName(getTypeName(metadata));
   var result:* = ClassUtils.newInstance(typeClass);

   for each (var m:Metadata in metadata)
   {
    if (m.name == "type")
     continue;

    // Attempting to invoke as method,
                // would really like the property though

    var methodInvoker:MethodInvoker = new MethodInvoker();

    methodInvoker.target = result;
    methodInvoker.method = m.name;
    methodInvoker.arguments = [m.value];

    var returnValue:* = methodInvoker.invoke(); // Fails!
   }

   return result;
  }

  private static function getTypeName(metadata:Array):String
  {
   if (metadata == null || metadata.length == 0)
    throw new ArgumentError("metadata is null or empty");

   var typeName:String;

   // Type is usually the first entry
   if (metadata.length > 1 && metadata[0] != null && metadata[0].name == "type")
   {
    typeName = metadata[0].value;
   }
   else
   {
    var typeMetadata:Array = metadata.filter(
     function(element:*, index:int, arr:Array):Boolean
     {
      return element.name == "type";
     }
    );

    if (typeMetadata == null || typeMetadata.length != 1)
     throw new ArgumentError("type entry not found in metadata");

    typeName = typeMetadata[0].value;
   }

   if (typeName == null || typeName.length == 0)
    throw new Error("typeName is null or blank");

   return typeName;
  }
 }
}

Вот некоторый код использования:


var metadata:Array = new Array();

metadata[0] = new Metadata("type", "mx.controls.Text", null);
metadata[1] = new Metadata("text", "Hello World!", null);
metadata[2] = new Metadata("x", "77", null);
metadata[3] = new Metadata("y", "593", null);

this.addChild(new UIComponentBuilder().build(metadata));

Я понимаю, что мне нужно объявить фиктивную переменную того типа, который я должен был создать, или использовать директиву компилятора -inculde. Несчастный недостаток Flex.

Кроме того, прямо сейчас есть код для учета типизации значения в указанном типе.

1 Ответ

1 голос
/ 17 февраля 2010

Динамическое выполнение в AS3 намного проще, чем в других языках. Этот код:

var methodInvoker:MethodInvoker = new MethodInvoker();

methodInvoker.target = result;
methodInvoker.method = m.name;
methodInvoker.arguments = [m.value];

var returnValue:* = methodInvoker.invoke(); // Fails!

можно упростить до этого:

var returnValue:* = result[method](m.value);

EDIT

Поскольку это свойство, это будет сделано так:

result[method] = m.value;

и возвращаемого значения нет (ну, вы можете снова вызвать метод получения, но он должен просто вернуть m.value, если только установщик / получатель не сделает что-нибудь напуганное.

...