【问题标题】:How do I dynamically instantiate a class, and set a property at runtime in Flex 3?如何在 Flex 3 中动态实例化一个类并在运行时设置一个属性?
【发布时间】:2010-02-17 18:22:24
【问题描述】:

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

我有一个 Metadata 类,它存储 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 的一个不幸的缺点。

另外,现在有代码可以将值类型转换为指定的类型。

【问题讨论】:

    标签: apache-flex actionscript-3 reflection actionscript flex3


    【解决方案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 做一些时髦的事情。

    【讨论】:

    • 这对于减少代码和 MethodInvoker 依赖性非常有用。但是,在我的情况下它仍然失败,因为我真的想设置一个属性值。例如,使用我上面指定的示例元数据,当它到达等于 result["text"]("Hello World!"): TypeError: Error #1006: value is not a function 时会失败。我确定这是因为没有等效于“文本”属性的方法。知道如何让它与属性一起使用吗?我认为在某些语言中没有相应的“setText”方法。不过我可能是错的。
    • @Edward Stembler,你试过result[method] = m.value; 吗?如果是属性,则将其设置为属性。
    • 好吧,我删除了 MethodInvoker 代码并用 var returnValue:* = result[m.name](m.value);这与 result["text"]("Hello World!"); 相同。方法是对象,还是可以使用字符串来引用方法(或属性)?
    • 没关系。我能够在没有 AS3 Commons Reflect 库的情况下让它工作。不确定我的原始代码有什么问题。我注意到“文本”属性实际上显示为访问器。无论如何,您的建议有效。
    • 我在原始代码中看到了我的问题。我仍然让它调用了不正确的方式 result[method](value),而我的测试代码使用了正确的方式 result[method] = value。
    猜你喜欢
    • 1970-01-01
    • 2012-06-24
    • 1970-01-01
    • 2019-05-20
    • 1970-01-01
    • 2014-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多