7.9 KiB
7.9 KiB
Platform Reflection Quick Start Guide
This guide covers the most common use cases for Platform Reflection to help you get started quickly.
Installation
dependencies:
platform_reflection: ^0.1.0
Basic Usage
1. Simple Class Reflection
import 'package:platform_reflection/reflection.dart';
// 1. Define your class
@reflectable
class User {
String name;
int age;
User(this.name, this.age);
void birthday() => age++;
}
// 2. Register for reflection
void main() {
// Register class
Reflector.register(User);
// Register properties
Reflector.registerProperty(User, 'name', String);
Reflector.registerProperty(User, 'age', int);
// Register methods
Reflector.registerMethod(
User,
'birthday',
[],
true,
);
// Register constructor
Reflector.registerConstructor(
User,
'',
parameterTypes: [String, int],
parameterNames: ['name', 'age'],
creator: (String name, int age) => User(name, age),
);
// Use reflection
final user = reflector.createInstance(
User,
positionalArgs: ['John', 30],
) as User;
final mirror = reflector.reflect(user);
print(mirror.getField(const Symbol('name')).reflectee); // John
mirror.invoke(const Symbol('birthday'), []);
print(mirror.getField(const Symbol('age')).reflectee); // 31
}
2. Property Access
// Get property value
final mirror = reflector.reflect(instance);
final name = mirror.getField(const Symbol('name')).reflectee as String;
// Set property value
mirror.setField(const Symbol('name'), 'Jane');
// Check if property exists
final metadata = Reflector.getPropertyMetadata(User);
if (metadata?.containsKey('name') ?? false) {
// Property exists
}
3. Method Invocation
// Invoke method without arguments
mirror.invoke(const Symbol('birthday'), []);
// Invoke method with arguments
final result = mirror.invoke(
const Symbol('greet'),
['Hello'],
).reflectee as String;
// Invoke method with named arguments
final result = mirror.invoke(
const Symbol('update'),
[],
{const Symbol('value'): 42},
).reflectee;
4. Constructor Usage
// Default constructor
final instance = reflector.createInstance(
User,
positionalArgs: ['John', 30],
) as User;
// Named constructor
final instance = reflector.createInstance(
User,
constructorName: 'guest',
) as User;
// Constructor with named arguments
final instance = reflector.createInstance(
User,
positionalArgs: ['John'],
namedArgs: {const Symbol('age'): 30},
) as User;
5. Type Information
// Get type metadata
final metadata = Reflector.getTypeMetadata(User);
// Check properties
for (var property in metadata.properties.values) {
print('${property.name}: ${property.type}');
}
// Check methods
for (var method in metadata.methods.values) {
print('${method.name}(${method.parameterTypes.join(', ')})');
}
6. Error Handling
try {
// Attempt reflection
final mirror = reflector.reflect(instance);
mirror.invoke(const Symbol('method'), []);
} on NotReflectableException catch (e) {
print('Type not registered: $e');
} on MemberNotFoundException catch (e) {
print('Member not found: $e');
} on InvalidArgumentsException catch (e) {
print('Invalid arguments: $e');
} on ReflectionException catch (e) {
print('Reflection error: $e');
}
Common Patterns
1. Registration Helper
void registerType<T>(Type type) {
Reflector.register(type);
final scanner = Scanner();
final metadata = scanner.scanType(type);
// Register properties
for (var property in metadata.properties.values) {
Reflector.registerProperty(
type,
property.name,
property.type,
isWritable: property.isWritable,
);
}
// Register methods
for (var method in metadata.methods.values) {
Reflector.registerMethod(
type,
method.name,
method.parameterTypes,
method.returnsVoid,
parameterNames: method.parameters.map((p) => p.name).toList(),
isRequired: method.parameters.map((p) => p.isRequired).toList(),
);
}
}
2. Property Observer
class PropertyObserver {
final InstanceMirror mirror;
final Symbol propertyName;
final void Function(dynamic oldValue, dynamic newValue) onChange;
PropertyObserver(this.mirror, this.propertyName, this.onChange);
void observe() {
var lastValue = mirror.getField(propertyName).reflectee;
Timer.periodic(Duration(milliseconds: 100), (_) {
final currentValue = mirror.getField(propertyName).reflectee;
if (currentValue != lastValue) {
onChange(lastValue, currentValue);
lastValue = currentValue;
}
});
}
}
3. Method Interceptor
class MethodInterceptor {
final InstanceMirror mirror;
final Symbol methodName;
final void Function(List args, Map<Symbol, dynamic> named) beforeInvoke;
final void Function(dynamic result) afterInvoke;
MethodInterceptor(
this.mirror,
this.methodName,
{this.beforeInvoke = _noOp,
this.afterInvoke = _noOp});
static void _noOp([dynamic _]) {}
dynamic invoke(List args, [Map<Symbol, dynamic>? named]) {
beforeInvoke(args, named ?? {});
final result = mirror.invoke(methodName, args, named).reflectee;
afterInvoke(result);
return result;
}
}
Best Practices
-
Register Early
void main() { // Register all types at startup registerType<User>(); registerType<Order>(); registerType<Product>(); // Start application runApp(); }
-
Cache Mirrors
class UserService { final Map<User, InstanceMirror> _mirrors = {}; InstanceMirror getMirror(User user) { return _mirrors.putIfAbsent( user, () => reflector.reflect(user), ); } }
-
Handle Errors
T reflectSafely<T>(Function() operation, T defaultValue) { try { return operation() as T; } on ReflectionException catch (e) { print('Reflection failed: $e'); return defaultValue; } }
-
Validate Registration
bool isFullyRegistered(Type type) { final metadata = Reflector.getTypeMetadata(type); if (metadata == null) return false; // Check properties if (metadata.properties.isEmpty) return false; // Check methods if (metadata.methods.isEmpty) return false; // Check constructors if (metadata.constructors.isEmpty) return false; return true; }
Common Issues
-
Type Not Registered
// Wrong reflector.reflect(unregisteredInstance); // Right Reflector.register(UnregisteredType); reflector.reflect(instance);
-
Missing Property/Method Registration
// Wrong Reflector.register(User); // Right Reflector.register(User); Reflector.registerProperty(User, 'name', String); Reflector.registerMethod(User, 'greet', [String]);
-
Wrong Argument Types
// Wrong mirror.invoke(const Symbol('greet'), [42]); // Right mirror.invoke(const Symbol('greet'), ['Hello']);
Performance Tips
-
Cache Metadata
final metadata = Reflector.getTypeMetadata(User); final properties = metadata.properties; final methods = metadata.methods;
-
Reuse Mirrors
final mirror = reflector.reflect(instance); // Reuse mirror for multiple operations
-
Batch Registration
void registerAll() { for (var type in types) { registerType(type); } }
Next Steps
- Read the Technical Specification for detailed implementation information
- Check the API Reference for complete API documentation
- See the Mirrors Comparison for differences from dart:mirrors