Search code examples
dartgetter-settergeneric-programming

Generic getter/setter in Dart?


I need a generic way to access an object's property/getter.

In JavaScript this can be done via

const obj = {
    foo: 'Hello World',
    bar: 123
};

const propName = 'foo';
console.log(o[propName]); // "Hello World"

So, if I had a class in Dart, like the one below, how would I access a property in a generic way? Maybe with operator overloading or something?

class MyFooClass with ChangeNotifier {
  String _someText = 'Hello World';
  int _someNumber = 123;

  get someText => _someText;
  set someText(value) => _someText = value;

  get someNumber => _someNumber;
  set someNumber(value) => _someNumber = value;
}

var myFoo = MyFooClass();
print(myFoo['someText']); // The operator '[]' isn't defined for the class 'MyFooClass'

Solution

  • It's possible using dart:mirrors (note that I have removed a few things to make it compile on its own):

    import 'dart:mirrors';
    
    class MyFooClass {
      String _someText = 'Hello World';
      int _someNumber = 123;
    
      get someText => _someText;
      set someText(value) => _someText = value;
    
      get someNumber => _someNumber;
      set someNumber(value) => _someNumber = value;
    
      operator [](String name) {
        InstanceMirror i = reflect(this);
    
        for (DeclarationMirror declMirror in i.type.declarations.values) {
          if (declMirror.isPrivate) {
            continue;
          }
    
          Symbol simpleName = declMirror.simpleName;
    
          // It's not possible to get the name from a symbol directly: https://github.com/dart-lang/sdk/issues/28372
          if (simpleName.toString() == 'Symbol("${name}")') {
            return i.getField(simpleName).reflectee;
          }
        }
      }
    }
    

    Use it like:

    void main() {
      var myFoo = MyFooClass();
      print(myFoo['someText']); // 'Hello, World!'
      print(myFoo['someNumber']); // 123
      print(myFoo['some non existent thing']); // null
    }
    

    Old answer

    Is this what you want?

    void main() {
      var o = {'foo': 'Hello World', 'bar': 123};
      var propName = 'foo';
    
      print(o[propName]); // 'Hello World'
    }