【问题标题】:How can you make dynamic getters/setters in dart如何在 dart 中制作动态 getter/setter
【发布时间】:2014-06-17 01:47:34
【问题描述】:

我正在尝试重新创建 djangos QueryDict 功能并制作一个可以给定 Map 的对象,它是对象中的私有变量,并且 getter/setter 用于动态地从地图中提取。我已经设法重新创建它的 get() 方法,但我在动态获取价值时迷失了方向。这是我目前所拥有的:

class QueryMap {
  Map _data;

  QueryMap(Map this._data);

  dynamic get(String key, [var defaultValue]) {
    if(this._data.containsKey(key)) {
      return this._data[key];
    } else if(defaultValue) {
      return defaultValue;
    } else {
      return null;
    }
  }
}

这里是 djangos 页面,了解它是如何工作的: https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.QueryDict.getitem

【问题讨论】:

    标签: dart dart-mirrors


    【解决方案1】:

    您可以覆盖noSuchMethod(emulating functions)

    @proxy
    class QueryMap {
      Map _data = new Map();
    
      QueryMap();
    
      noSuchMethod(Invocation invocation) {
        if (invocation.isGetter) {
          var ret = _data[invocation.memberName.toString()];
          if (ret != null) {
            return ret;
          } else {
            super.noSuchMethod(invocation);
          }
        }
        if (invocation.isSetter) {
          _data[invocation.memberName.toString().replaceAll('=', '')] =
              invocation.positionalArguments.first;
        } else {
          super.noSuchMethod(invocation);
        }
      }
    }
    void main() {
      QueryMap qaueryMap = new QueryMap();
      qaueryMap.greet = "Hello Dart!";
      print(qaueryMap.greet); //Hello Dart!
    }
    

    正如 @PixelElephant 所述,对于外部映射,您必须使用真实的方法名称作为映射键:

    import 'dart:mirrors';
    @proxy
    class QueryMap {
      Map _data;
    
      QueryMap(this._data);
    
      noSuchMethod(Invocation invocation) {
        if (invocation.isGetter) {
          var ret = _data[MirrorSystem.getName(invocation.memberName)];
          if (ret != null) {
            return ret;
          } else {
            super.noSuchMethod(invocation);
          }
        }
        if (invocation.isSetter) {
          _data[MirrorSystem.getName(invocation.memberName).replaceAll('=', '')] =
              invocation.positionalArguments.first;
        } else {
          super.noSuchMethod(invocation);
        }
      }
    }
    void main() {
      Map myMap = new Map();
      myMap["color"] = "red";
      QueryMap qaueryMap = new QueryMap(myMap);
      qaueryMap.greet = "Hello Dart!";
      print(qaueryMap.greet); //Hello Dart!
      print(qaueryMap.color); //red
    }
    

    为避免使用镜像,您可以对符号的字符串序列化进行模式匹配或转换外部映射键:

    @proxy
    class QueryMap {
      Map _data;
    
      QueryMap(Map data) {
        _data = new Map();
        data.forEach((k, v) => _data[new Symbol(k).toString()] = v);
      }
    
      noSuchMethod(Invocation invocation) {
        if (invocation.isGetter) {
          var ret = _data[invocation.memberName.toString()];
          if (ret != null) {
            return ret;
          } else {
            super.noSuchMethod(invocation);
          }
        }
        if (invocation.isSetter) {
          _data[invocation.memberName.toString().replaceAll('=', '')] =
              invocation.positionalArguments.first;
        } else {
          super.noSuchMethod(invocation);
        }
      }
    }
    void main() {
      Map myMap = new Map();
      myMap["color"] = "red";
      QueryMap qaueryMap = new QueryMap(myMap);
      qaueryMap.greet = "Hello Dart!";
      print(qaueryMap.greet); //Hello Dart!
      print(qaueryMap.color); //red
    }
    

    【讨论】:

    • 请注意memberName 是Symbol,您应该在其上调用MirrorSystem.getName 以获取可以用作键的字符串(而不是toString)。
    • @PixelElephant 我尽量避免使用任何形状或形式的镜子,因为它们会影响性能。
    • 是的,但是这里需要它们。您的代码之所以有效,是因为您既设置又使用 noSuchMethod。如果您使用了已经创建的地图,例如Map map = {'greet': 'Hello Dart'};,代码将失败,因为它试图获取Symbol('greet') 而不仅仅是greet。
    • @PixelElephant 谢谢这是一个有效的观点。我忘了它使用外部地图。
    • 这真是个天才!所以我猜最后一种方法也适用于不允许镜子的颤振?还有没有人知道使用这个对性能的影响?它确实有助于减少我们代码库中的大量样板,所以我很想使用它
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-25
    • 1970-01-01
    • 2020-02-20
    • 2012-04-15
    • 1970-01-01
    相关资源
    最近更新 更多