在Dart中动态填充父字段

时间:2014-01-05 13:48:59

标签: dart dart-mirrors

我正在从Map数据动态创建对象,填充字段以匹配键名。在父节点上定义字段时会出现问题,尝试在父字段上设置值会产生错误:

No static setter 'name' declared in class 'Skill'.

  NoSuchMethodError : method not found: 'name'

代码:

class Resource {
  String name;
  String description;

  Resource.map(Map data)
  {
    ClassMirror c = reflectClass(runtimeType);
    ClassMirror thisType = c;
    while(c != null)
    {
      for (var k in c.declarations.keys) {
        print('${MirrorSystem.getName(k)} : ${data[MirrorSystem.getName(k)]}');
        if(data[MirrorSystem.getName(k)] != null)
        {
          thisType.setField(k, data[MirrorSystem.getName(k)]);        
        }
      }
      c = c.superclass;
    }
  }
}

class Skill extends Resource
{
  Skill.map(data) : super.map(data);
}

3 个答案:

答案 0 :(得分:5)

您应该使用ObjectMirror在对象上设置字段。您的代码尝试在ClassMirror上设置一个字段,该字段尝试定义静态变量

class Resource {
  String name;
  String description;

  Resource.map(Map data)
  {
    ObjectMirror o = reflect(this);  // added
    ClassMirror c = reflectClass(runtimeType);
    ClassMirror thisType = c;
    while(c != null)
    {
      for (var k in c.declarations.keys) {
        print('${MirrorSystem.getName(k)} : ${data[MirrorSystem.getName(k)]}');
        if(data[MirrorSystem.getName(k)] != null)
        {
          // replace "thisType" with "o"
          o.setField(k, data[MirrorSystem.getName(k)]);
        }
      }
      c = c.superclass;
    }
  }
}

class Skill extends Resource
{
  Skill.map(data) : super.map(data);
}

答案 1 :(得分:3)

Dart中不会继承静态方法/字段 这里已经有一些关于这种行为的讨论了 您可以查看此问题的答案in Dart, using Mirrors, how would you call a class's static method from an instance of the class?

如果您尝试访问的方法/字段不是静态的,请提供更多代码(您要反映的类/对象)

答案 2 :(得分:1)

此示例更安全,因为它执行其他操作:

  • 仅查询指定的类型成员。
  • 执行类型兼容性检查。
  • 尝试转换值。
import 'package:reflection/reflection.dart';

class ObjectFiller {
  static void fill(Object obj, Map map) {
    var ti = typeInfo(obj.runtimeType);
    // Query only specified type members
    for(VariableInfo vi in ti.getVariables(BindingFlags.PUBLIC |
      BindingFlags.INSTANCE).values) {
      var name = SymbolHelper.getName(vi.simpleName);
      if(map.containsKey(name)) {
        var value = map[name];
        // Perform type compatibility checks.
        if(typeInfo(value.runtimeType).isAssignableFrom(vi.type)) {
          vi.setValue(obj, value);
        } else {
          // Try convert values.
          if(value is String) {
            if(typeInfo(int).isAssignableFrom(vi.type)) {
              try {
                vi.setValue(obj, int.parse(value));
              } catch(e) {
              }
            }
          }
        }
      }
    }
  }
}

void main() {
  var objects = [];
  // null object
  objects.add([null, {"foo" : 41}]);
  // Zebra object (without one front tooth)
  // Slipped, fell, woke up - one tooth missing
  objects.add([new Zebra(), {"numberOfTeeth" : "43", "numberOfStripes" : 30}]);
  // Zebra object
  objects.add([new Zebra(), {"numberOfTeeth" : 44, "numberOfStripes" : 40}]);
  // Filling  objects
  for(var object in objects) {
    ObjectFiller.fill(object[0], object[1]);
  }
  // Dumping objects (full)
  for(var object in objects) {
    var obj = object[0];
    print("Full dump of ${obj}");
    print(objectToMap(obj));
    print("---------------------------");
  }
  // Dumping objects (short)
  for(var object in objects) {
    var obj = object[0];
    print("Short dump of ${obj}");
    print(objectToMap(obj, true));
    print("---------------------------");
  }
}

Map objectToMap(Object obj, [bool declaredOnly = false]) {
  var map = {};
  if(obj == null) {
    return map;
  }

  var flags = BindingFlags.PUBLIC | BindingFlags.INSTANCE;
  if(declaredOnly) {
    flags |= BindingFlags.DECLARED_ONLY;
  }

  var ti = typeInfo(obj.runtimeType);
  for(VariableInfo vi in ti.getVariables(flags).values) {
    var name = SymbolHelper.getName(vi.simpleName);
    map[name] = vi.getValue(obj);
  }

  for(PropertyInfo pi in ti.getProperties(flags).values) {
    if(pi.isGetter) {
      var name = SymbolHelper.getName(pi.simpleName);
      map[name] = pi.getValue(obj);
    }
  }

  return map;
}

abstract class Animal {
  static String unusedInAnimal;

  int numberOfTeeth = 0;

  String get family;
}

class Zebra extends Animal {
  static String unusedInZebra;

  int numberOfStripes = 0;

  String get family => "Equidae";
}
Full dump of null
{}
---------------------------
Full dump of Instance of 'Zebra'
{numberOfTeeth: 43, numberOfStripes: 30, hashCode: 970552119, runtimeType: Zebra, family: Equidae}
---------------------------
Full dump of Instance of 'Zebra'
{numberOfTeeth: 44, numberOfStripes: 40, hashCode: 1024653070, runtimeType: Zebra, family: Equidae}
---------------------------
Short dump of null
{}
---------------------------
Short dump of Instance of 'Zebra'
{numberOfStripes: 30, family: Equidae}
---------------------------
Short dump of Instance of 'Zebra'
{numberOfStripes: 40, family: Equidae}
---------------------------