Reputation: 7252
I have this method
void doSomething<T>() { ... }
and a variable of type T
T someVar = ...;
how can I use doSomething
method to perform an action on someVar
, something like this?
doSomething<someVar.Type>();
in fact, I want to access Type T
form variable.
here is the example
class BlocManagerProvider extends StatefulWidget {
const BlocManagerProvider({
@required this.child,
@required this.blocs,
Key key,
}) : super(key: key);
final Widget child;
final List<Cubit<Object>> blocs;
@override
_BlocManagerProviderState createState() => _BlocManagerProviderState();
}
class _BlocManagerProviderState extends State<BlocManagerProvider> {
@override
Widget build(BuildContext context) => widget.child;
@override
void dispose() {
for (final Cubit<Object> bloc in widget.blocs) {
BlocManager.instance.dispose<type>();
}
super.dispose();
}
}
Future<void> dispose<T extends Cubit<Object>>() async {
final String objectKey = _getKey<T>(key);
if (_repository.containsKey(objectKey)) {
await _repository[objectKey].close();
_repository.remove(objectKey);
await removeListener<T>(key);
}
}
Upvotes: 1
Views: 1540
Reputation: 71903
Dart does not provide a way to go from an object of type X
to a type variable bound to X
. There are good technical reasons for not allowing that (it allows the web compilers to know at compile-time which types can ever be bound to a type variable, which allows it to reduce the compiled code).
The dispose
method is treating the type argument as its only argument and acting on the value of that type argument.
It makes me think you're trying to do something that the language is not designed for.
You're passing in a type argument, and then the code inspects that type of argument and behaves differently depending on the value. That's not what's usually meant by being "generic" - to act the in the same (generic) way independently of the types, so the only real effect of passing a type is to make the return type match the argument type. (That's why Java can erase type arguments at run-time).
So, if you need to know a type for some object, either that object must provide it for you, or you have to store it from earlier (perhaps when the object was created).
So, if you really need to access the type argument that the cubit is implementing Cubit<X>
of, the Cubit
class needs to make it available to you. That will usually be with a method with a callback (like a visitor), something like:
abstract class Cubit<T> ... {
...
R visit<R>(R Function<C extends Cubit<T>, T>(C value) action);
}
class SomeCubit<T> extends Cubit<T> {
...
R visit<R>(R Function<C extends Cubit<T>, T>(C value) action) =>
action<SomeCubit<T>, T>(this);
}
If something like that's available, then you can do what you want as:
bloc.visit(<C extends Cubit<T>, T>(_) => BlocManager.instance.dispose<C>());
If something like that is not available, then you are in trouble.
You can detect a number of known types, with a bunch of if
statements, but that's unlikely to be sufficient.
That means you need to remember the type from earlier, but since it looks like you just get a List<Cubit<Object>>
that has already been created, that doesn't seem practical either.
If the BlocManager
is your own class, consider changing it to use Type
objects instead of type arguments (which is contrary to everything I usually say you should do), because then you can call ..dispose(bloc.runtimeType)
. I'd prefer to avoid that, but if other constraints make what you do impossible, then it might be the lesser evil.
Upvotes: 2