如何在Flex 3中动态实例化类,并在运行时设置属性?

时间:2010-02-17 18:22:24

标签: flex actionscript-3 reflection actionscript flex3

使用org.as3commons.reflect我可以查找类名,并在运行时实例化一个类。我也有(非工作)代码调用方法。但是,我真的想设置一个属性值。我不确定属性是否在Flex内部实现为方法。

我有一个Metadata类,它存储3条信息:名称,值和类型(都是字符串)。我希望能够遍历Metadata对象数组并在实例化的类上设置相应的属性。


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 个答案:

答案 0 :(得分:1)

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);

修改

因为它是一个属性,所以会这样做:

result[method] = m.value;

并且没有返回值(好吧,你可以再次调用getter但它应该只返回m.value,除非setter / getter做一些时髦的事情。