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');
}
}
Related
Is there any way using which I can return a Class as a function return type?
My sample code:
class Data_1{
static int price = 1;
}
class Data_2{
static int price = 2;
}
getData() {
if (widget.data_name == "Data_1"){
return Data_1;
} else if (widget.data_name == "Data_2"){
return Data_2;
}
}
void print_price() {print(getData.price);}
Using the above code getting the below error:
The getter 'price' isn't defined for the type 'dynamic Function()'.
Try importing the library that defines 'price', correcting the name to the name of an existing getter, or defining a getter or field
named 'names'.
There are a few issues with the code above, to fix them:
We should define a property getter in the classes:
class Data_1 {
static int _price = 1;
get price => _price;
}
class Data_2 {
static int _price = 2;
get price => _price;
}
getData() should return an instance of the class, not the Type:
getData() {
if (widget.data_name == "Data_1")
{return Data_1();} // not Data_1
else if (widget.data_name == "Data_2")
{return Data_2();} } // not Data_2
}
We can now call the getData() function and access the price getter:
void main() {
print(getData().price);
}
Follows the full code example:
class Data_1 {
static int _price = 1;
get price => _price;
}
class Data_2 {
static int _price = 2;
get price => _price;
}
getData() {
return Data_1();
}
void main() {
print(getData().price);
}
There are several models have a same structure, { type: xxx, settings: xxx}, so i would like to use a parent class "WidgetConfig" with a generic type "T" to implement this, but problem occurs when i add "fromJson" methods. How can i invoke method on a generic type or any other ways to implement this?
class BannerWidgetViewModel extends ChangeNotifier {
WidgetConfig<BannerWidgetConfig> config;
BannerWidgetViewModel(String configJson){
config = WidgetConfig.fromJson(configJson);
}
}
class BannerWidgetConfig {
String imgUrl;
String padImgUrl;
String lessonId;
BannerWidgetConfig.fromJson(json){
if (json != null) {
this.imgUrl = json['imgUrl'];
this.padImgUrl = json['padImgUrl'];
this.lessonId = json['lessonId'];
}
}
}
class WidgetConfig<T> {
WidgetType type;
WidgetConfig.fromJson(json){
if (json != null) {
this.type = json['type'];
// this.settings = T.fromJson(json['settings']); // T doesn't have fromJson method
}
}
}
then i use a abstract class but still not working.
abstract class BaseWidgetConfig {
BaseWidgetConfig.fromJson(dynamic json);
}
class WidgetConfig<T extends BaseWidgetConfig> {
WidgetType type;
T settings;
WidgetConfig.fromJson(json){
if (json != null) {
this.type = json['type'];
this.settings = T.fromJson();
}
}
}
code picture
Directly show the function as a reference.
send function as a reference here.
FireStoreHelper.getList<ModelLesson>('grade4', ModelLesson.fromJson);
get the method here.
static Future<List<T>> getList<T>(String path, Function fromJson)
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();
}
}
}
Assume two unrelated classes (from Flutter libraries, etc):
class A {
String name;
}
class B {
int age;
}
Is it possible to have a List<A/B>? I know it's possible to have List<dynamic> but that would allow for Cs, Ds and Zs to be accepted as well.
You can create a parent abstract class for A and B and add a List which only allows children from the parent class.
abstract class Foo {
}
class A extends Foo {
}
class B extends Foo {
}
class C {
}
This is correct:
List<Foo> items = [A(), B()];
This isn't
List<Foo> items = [A(), B(),C()];
And you can identify the type with your own variable or using the runtimeType
for(Foo item in items){
print(item.runtimeType);
}
Another option (long version)
class Bar {
final A a;
final B b;
Bar({this.a, this.b}) {
if (a == null && b == null || a != null && b != null) throw ArgumentError("only one object is allowed");
}
}
class A {
}
class B {
}
class C {
}
Usage
List<Bar> items = [Bar(a: A()), Bar(b: B())];
for(Bar item in items){
if (item.a != null) print("Item : ${item.a}");
if (item.b != null) print("Item : ${item.b}");
}
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
}
}