Is there a way to loop over the custom types in flutter.
class Square {}
class Rectangle {}
getShape<T>() {
if(T is Square) {
return Square();
}
}
void main() {
List shapes = [Square, Rectangle];
for (dynamic T in shapes) {
getShape<T>();
}
}
In the above code, T is not getting identified.
You can use it like this:
class Square {}
class Rectangle {}
getShape(T) {
print(T is Rectangle);
if(T is Square) {
return Square();
}
}
void main() {
List shapes = [Square(), Rectangle()];
for (dynamic T in shapes) {
getShape(T);
}
}
The code produces this diagnostic because T is a variable, not a type:
Dart documentation
Either you can send it as the Function argument
getShape(T){}
or
getShape<T>(){}
then
for (final T in shapes) {
if (T == Square) {
print(getShape<Square>());
}
}
You can't really do a lot of useful things with Type objects. You can, however, use them as keys in a Map:
class Square {}
class Rectangle {}
final shapeFactories = <Type, dynamic Function()>{
Square: () => Square(),
Rectangle: () => Rectangle(),
};
void main() {
var shapes = <Type>[Square, Rectangle];
for (var T in shapes) {
var shape = shapeFactories[T]!();
print(shape.runtimeType);
}
}
Related
in my Flutter project, I want to decide class member type during execution. For this, I wrote the following code with the help of this entry: https://github.com/flutter/flutter/issues/17766 But I cannot access function printt(). It gives error: The method 'printt' isn't defined for the type 'Object'.
void main() {
Merchant merchant = Merchant('A');
merchant.mp!.printt(); // this line gives error: The method 'printt' isn't defined for the type 'Object'.
}
class Merchant {
Object? mp;
Merchant(String mpStr) {
if (mpStr == 'A') mp = createInstanceOf<A>();
if (mpStr == 'B') mp = createInstanceOf<B>();
}
T? createInstanceOf<T>() {
final factories = <Type, T Function()>{
A: () => A() as T,
B: () => B() as T,
};
final createInstance = factories[T];
return createInstance?.call(); // Same as createInstance() but null safety
}
}
class A {
void printt() {
print('I am function of class A');
}
}
class B {
void printt() {
print('I am function of class B');
}
}
Like #Yannis mentioned, create an abstract class, let's say PrintT, with all common methods of A and B and set mp as this type. Then, set both class A and B to implement it. The code is going to be the following:
Check out the live demo on DartPad.
void main() {
Merchant merchant = Merchant('A');
merchant.mp!.printt();
}
class Merchant {
PrintT? mp;
Merchant(String mpStr) {
if (mpStr == 'A') mp = createInstanceOf<A>();
if (mpStr == 'B') mp = createInstanceOf<B>();
}
T? createInstanceOf<T>() {
final factories = <Type, T Function()>{
A: () => A() as T,
B: () => B() as T,
};
final createInstance = factories[T];
return createInstance?.call(); // Same as createInstance() but null safety
}
}
abstract class PrintT {
void printt();
}
class A implements PrintT {
void printt() {
print('I am function of class A');
}
}
class B implements PrintT {
void printt() {
print('I am function of class B');
}
}
I am trying to access current value of map that is in class level method from outside the function.
//This is function for call back
fireAlaram(String message_map) {
Assistant(message_map).speak();
}
//this is the function that is in stateful class
void do_backgroundTask() {
var ke = todoBox.keys.cast<int>().toList();
if (ke.length > 0) {
for (var _k in ke) {
if (todoBox.get(_k)!.time.compareTo(DateTime.now()) >= 0) {
m.addAll(todoBox.get(_k)!.toMap());
}
}
if (m.length > 0) {
products = m.keys.toList();
products.sort();
setState(() {
t = products[0];
});
AndroidAlarmManager.oneShotAt(t, 1,fireAlaram(m[t])
);
}
}
}
I want to get value of map string value when key is t, it gives null error
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?
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();
}
}
}
I'm making a plugin for Aurelia and need a class decorator that
adds attributes to the new object instance, and
calls an external function with the new object as an argument.
I've looked through examples, and so far I've put together ("pseudo-ish" code)
return function addAndCall(target: any): any {
var original = target;
var newConstructor = function (...args) {
original.apply(this, args);
this.newAttribute = "object instance value";
ExternalModule.externalFunction(this);
};
newConstructor.prototype = Object.create(original.prototype);
newConstructor.prototype.constructor = original;
return <any>newConstructor;
}
but
I'm not entirely clear on the details here (or what is actually needed), and
it might not work properly since I'm getting Aurelia errors when using objects instantiated from classes with this decorator (and I suspect it's my decorator rather than the Aurelia framework that's buggy).
Any help and explanation would be greatly appreciated!
Why not just assign those properties to the prototype, and subsequently assign to the instance on first invocation
// decorator
function addAndCall(cb: Function, newField: string) {
// cb is now available in the decorator
return function(ctor: Function): void {
Object.defineProperty(ctor.prototype, newField, {
value: function(...args: any[]) {
return Object.defineProperty(this, newField, {
value: function(...args: any[]) {
console.log(newField, ...args);
}
})[newField](...args);
}
});
cb(ctor);
}
}
let callMe = (decoratedCtor) => console.log(decoratedCtor);
#addAndCall(callMe, 'propertyName')
class AddToMe {}
let addToMe = new AddToMe();
(<any>addToMe).propertyName(1, 2);
Here's a working version:
function addAndCall(target: any) {
var original = target;
function construct(constructor, args) {
var c: any = function () {
this.newAttribute = "object instance value";
ExternalModule.externalFunction(this);
return constructor.apply(this, args);;
}
c.prototype = constructor.prototype;
return new c();
}
var f: any = function (...args) {
return construct(original, args);
}
f.prototype = original.prototype;
return f;
}
(code in playground)
If so, how is this accomplished? If not, are there any plans to support this in future Dart releases? I'm mostly referring to your own created custom annotations.
In this documentation link, https://www.dartlang.org/docs/spec/latest/dart-language-specification.html#h.d0rowtffuudf, it says: "Metadata is associated with the abstract syntax tree of the program construct p that immediately follows the metadata, assuming p is not itself metadata or a comment . Metadata can be retrieved at runtime via a reflective call, provided the annotated program construct p is accessible via reflection.
Reflective access to metadata is not yet implemented as of the M3 release."
Thank you.
Sample code for understanding.
import "dart:mirrors";
void main() {
var object = new Class1();
var classMirror = reflectClass(object.runtimeType);
// Retrieve 'HelloMetadata' for 'object'
HelloMetadata hello = getAnnotation(classMirror, HelloMetadata);
print("'HelloMetadata' for object: $hello");
// Retrieve 'Goodbye' for 'object.method'
var methodMirror = (reflect(object.method) as ClosureMirror).function;
Goodbye goodbye = getAnnotation(methodMirror, Goodbye);
print("'Goodbye' for object: $goodbye");
// Retrieve all 'Goodbye' for 'object.method'
List<Goodbye> goodbyes = getAnnotations(methodMirror, Goodbye);
print("'Goodbye's for object.method': $goodbyes");
// Retrieve all metadata for 'object.method'
List all = getAnnotations(methodMirror);
print("'Metadata for object.method': $all");
}
Object getAnnotation(DeclarationMirror declaration, Type annotation) {
for (var instance in declaration.metadata) {
if (instance.hasReflectee) {
var reflectee = instance.reflectee;
if (reflectee.runtimeType == annotation) {
return reflectee;
}
}
}
return null;
}
List getAnnotations(DeclarationMirror declaration, [Type annotation]) {
var result = [];
for (var instance in declaration.metadata) {
if (instance.hasReflectee) {
var reflectee = instance.reflectee;
if (annotation == null) {
result.add(reflectee);
} else if (reflectee.runtimeType == annotation) {
result.add(reflectee);
}
}
}
return result;
}
#HelloMetadata("Class1")
class Class1 {
#HelloMetadata("method")
#Goodbye("method")
#Goodbye("Class1")
void method() {
}
}
class HelloMetadata {
final String text;
const HelloMetadata(this.text);
String toString() => "Hello '$text'";
}
class Goodbye {
final String text;
const Goodbye(this.text);
String toString() => "Goodbye '$text'";
}
Output:
'HelloMetadata' for object: Hello 'Class1'
'Goodbye' for object: Goodbye 'method'
'Goodbye's for object.method': [Goodbye 'method', Goodbye 'Class1']
'Metadata for object.method': [Hello 'method', Goodbye 'method', Goodbye 'Class1']
P.S.
If Dart had supported the generic methods that I would recommend to use this code.
T getAnnotation<T>(DeclarationMirror declaration) {
for (var instance in declaration.metadata) {
if (instance.hasReflectee) {
var reflectee = instance.reflectee;
if (reflectee.runtimeType == T) {
return reflectee;
}
}
}
return null;
}
And retrieve metadata with generic method.
var goodbye = getAnnotation<Goodbye>(methodMirror);
Yes you can retrieve annotations with dart:mirrors :
import 'dart:mirrors';
#override
class A {}
main(){
TypeMirror typeOfA = reflectType(A);
// or reflectType(a.runtimeType) if a is an instance of A
// getting metadata of the class
List<InstanceMirror> metadatas = typeOfA.metadata;
for (InstanceMirror m in metadatas) {
ClassMirror cm = m.type;
// here you get the Class of the annotation
}
}