I have this annotation:
class Handler {
final Function onListen;
final Function onPause;
final Function onResume;
final Function onCancel;
const Handler({this.onListen, this.onPause, this.onResume, this.onCancel});
}
and use it like this:
abstract class Test implements ViewModel<TestController> {
static onListen() {
print('onListen');
}
#Handler(onListen: onListen)
Stream<String> get messages;
factory Test() = _$Test;
Test._();
}
This works so far but is there a way to use a non static method as parameter for my annotation?
When I remove the static I get this error: Arguments of a constant creation must be constant expressions.
No, instance methods can't be const and annotations have to be const,
Therefore you can only have static methods or top-level functions as parameters for annotations.
Related
How can I pass-in non-constant method in Dart Annotations?
Here is my annotation:
class Injectable {
final String name;
final Scope scope;
final List<Provider>? provider;
const Injectable({this.name = '', this.scope = Scope.factory, this.provider});
}
class Provider<T> {
final Type? useClass;
final Object? useValue;
final T? Function()? usefactory;
final List<Type> deps;
const Provider(
{this.useClass, this.useValue, this.usefactory, this.deps = const []});
}
This works fine:
But when I try to directly pass-in the function. I am getting a compile error:
Any idea what is happening?
Error: Arguments of a constant creation must be constant expressions. (Documentation) Try making the argument a valid constant, or use 'new' to call the constructor.
Invalid constant value.
The argument type 'ServiceA' can't be assigned to the parameter type 'ServiceA? Function()?'. (Documentation)
Please try to remove the brackets from inject<ServiceA>(). Just make it inject<ServiceA>.
usefactory-s type is a function, but in your case, you are passing ServiceA type data.
I saw a tutorial where he declared a function like this:
class Person {
String name;
Function(String name) doingHobby;
}
What does it mean? how is it differ with common Function with bracket?
This also not even looks like arrow function.
Thanks.
It means that doingHobby is a variable which is allowed to point to as function which returns dynamic (if we don't specify any return value, Dart will assume dynamic which basically means it is allowed to return anything including void) and takes one String argument.
Here is an example where I assign a void Function(String) to it using a constructor and later calls this function by using the doingHobby variable:
class Person {
String name;
void Function(String name) doingHobby;
Person(this.name, this.doingHobby);
}
void main() {
final person = Person(
'Jakob',
(hobby) => print('Doing $hobby'),
);
person.doingHobby('playing football'); // Doing playing football
}
I want to invoke functions of a class by their names inside a string. I know my best option are Mirrors.
var ref = reflect(new TestClass());
ref.invoke(Symbol("test"), []);
It works fine, I can call the function test by a string. But I also want to put "TestClass" inside a string. Is it possible somehow ?
var ref = reflect("TestClass");
ref.invoke(Symbol("test"), []);
Jonas
You can do something like this:
import 'dart:mirrors';
class MyClass {
static void myMethod() {
print('Hello World');
}
}
void main() {
callStaticMethodOnClass('MyClass', 'myMethod'); // Hello World
}
void callStaticMethodOnClass(String className, String methodName) {
final classSymbol = Symbol(className);
final methodSymbol = Symbol(methodName);
(currentMirrorSystem().isolate.rootLibrary.declarations[classSymbol]
as ClassMirror)
.invoke(methodSymbol, <dynamic>[]);
}
Note, that this implementation does require that myMethod is static since we are never creating any object but only operate directly on the class itself. You can create new objects from the class by calling newInstance on the ClassMirror but you will then need to call the constructor.
But I hope this is enough. If not, please ask and I can try add some more examples.
I am trying to create a base class for my models but I am struggling with the error The name 'cls' isn't a type so it can't be used as a type argument.. So, how can I pass the object's constructor to the Hive.box method?
import 'package:hive/hive.dart';
class AppModel {
#HiveField(0)
int id;
#HiveField(1)
DateTime createdAt;
#HiveField(2)
DateTime updatedAt;
save() async {
final Type cls = this.runtimeType;
// The name 'cls' isn't a type so it can't be used as a type argument.
final Box box = await Hive.openBox<cls>(cls.toString());
await box.put(this.id, this);
return this;
}
}
#HiveType(typeId: 0)
class UserModel extends AppModel {
#HiveField(3)
String email;
#HiveField(4)
String displayName;
}
void main() {
final UserModel user = UserModel()
..email = 'user#domain.com'
..displayName = 'john doe';
user.save().then(() {
print('saved');
});
}
Dart does not have a way to refer to the dynamic type of this (a "self type").
The way such things are often handled is to have a self-type as type argument, so:
class AppModel<T extends AppModel> {
save() async {
final Box box = await Hive.openBox<T>(T.toString());
await box.put(this.id, this as T);
return this;
}
...
and then ensure that each subclass tells the superclass what type it is:
class UserModel extends AppModel<UserModel> {
...
}
(or, if you expect to subclass UserModel eventually:
class UserModel<T extends UserModel> extends AppModel<T> {
...
}
so that a subclass can still pass its type through).
You are also talking about constructors, and for that there is no easy solution.
Dart's type parameters are types, not classes. You cannot access static members or constructors from a type variable, and there is also no other way to pass a class around.
The only way you can have something call a constructor that it doesn't refer to statically, is to wrap the constructor call in a function and pass that function.
(I can't see how you need the constructor here).
I am new to Dart and Flutter. While I am going through tutorials, I got that we can make singleton using factory keyword. But after that, I got this code.
class AccountService {
static final _instance = AccountService._internal();
AccountService._internal();
static AccountService getInstance() {
return _instance;
}
}
My questions.
How does the code work?
when getInstance() get called?
is AccountService._internal() a constructor?
static final _instance = AccountService._internal(); - When this get called?
Please help me
Static fields in Dart are all lazy evaluated so they will first get its value the first time you access the field.
So:
When you call getInstance(), it will return the value of the field _instance. If this is the first time the field will be evaluated so AccountService._internal() is called. If it is second time, the value from previous access is reused.
First time you call the method somewhere in your code? If you are never calling the method, the object referenced by _instance will never be created.
Yes, it is a named constructor and because the name starts with "_" it is only available from the library this class is part of. By doing so, it is possible to restrict new objects from this class so only the class itself are allowed to create an instance.
It is called first time _instance is accessed. Since this name also starts with "_" it is only available from the library this class is part of.
The lazy initialization of static fields is described in the Dart specification with the following reasoning:
Static variable declarations with an initializing expression are initializedlazily (8.1).
The lazy semantics are given because we do not want a language where one tends to define expensive initialization computations, causing long application startup times. This is especially crucial for Dart, which must support the coding of client applications.
https://dart.dev/guides/language/specifications/DartLangSpec-v2.2.pdf
Added code example
class AccountService {
static final _instance = AccountService._internal();
AccountService._internal() {
print(':: Calling AccountService._internal constructor');
}
static AccountService getInstance() {
print(':: Calling getInstance()');
return _instance;
}
}
void main() {
print(':: Step 1');
AccountService.getInstance();
print(':: Step 2');
AccountService.getInstance();
print(':: End');
}
Output:
:: Start
:: Step 1
:: Calling getInstance()
:: Calling AccountService._internal constructor
:: Step 2
:: Calling getInstance()
:: End