I am trying to set a property from an external object:
main() {
A a = A();
print(a.prop.runtimeType); // is 'Null'
MiddleMan().b.assign(a.prop);
print(a.prop.runtimeType); // should be 'B', but is 'Null'
}
class A { B prop; }
class MiddleMan { B b = B(); }
class B {
assign(B property) { property = this; }
}
I managed to achieve this functionality with mirrors:
import 'dart:mirrors';
main() {
A a = A();
print(a.prop.runtimeType); // is 'Null'
MiddleMan().b.assign(a, 'prop');
print(a.prop.runtimeType); // is 'B'
}
class A { B prop; }
class MiddleMan { B b = B(); }
class B {
assign(dynamic object, String property) {
InstanceMirror reflectee = reflect(object);
reflectee.setField(Symbol(property), this);
}
}
But then I realized mirrors are disabled in Flutter. Is there any workaround?
Solution 1: Kaspi
Just as mentioned here, one can use a wrapper class:
main() {
A a = new A();
print(a.prop.value.runtimeType); // is 'Null'
MiddleMan().b.assign(a.prop);
print(a.prop.value.runtimeType); // is 'B'
}
class A {
Wrapper<B> prop = Wrapper(null);
}
class MiddleMan {
B b = B();
}
class B {
assign(Wrapper<B> property) {
property.value = this;
}
}
class Wrapper<T> {
T value;
Wrapper(this.value);
}
But because my intention is to write a library and make its use easy for the user, with one line call such as:
MiddleMan().b.assign(a.prop);
And at the same time I needed to optionally process additional stuff when the property is assigned, so a direct assignment like a.prop = MiddleMan().b;
, for now I decided to utilize somewhat unusual syntax with overloading the &
operator, which results in usage as:
a.prop = MiddleMan().b;
or optionally:
a.prop = MiddleMan().b & doAdditionalStuff;
Here's the implementation:
class B {
B operator &(Function doAdditionalStuff) {
if (doAdditionalStuff != null)
doAdditionalStuff();
return this;
}
}
To give it more sense of what I am trying to achieve, my lib is supposed to work in context with the Provider library. User code example:
class MyStore with ChangeNotifier {
B prop;
MyStore() {
// MiddleMan is Singleton
prop = MiddleMan().b;
// or alternatively
prop = MiddleMan().b & notifyListeners;
}
}
Library code example:
class B {
List<Function> _reactives = [];
B operator &(Function notifyListenersCallback) {
if (notifyListenersCallback != null)
this._reactives.add(notifyListenersCallback);
return this;
}
// called on each internally triggered change
notifyListeners() {
for (Function reactive in this._reactives) {
if (reactive != null)
reactive();
}
}
}