Dart: switch case of a class?
Asked Answered
R

4

4

Hello Guys, I hope you are doing well!

I got a question, it's how to use switch case on a class? (Here the 'state' is the main class, and other classes are inherited from state.)

like for example, I tried to replace this:

if(state is LoadingPage)        {return LoadingPage;}
else if {state is SuccessPage)  {return SuccessPage;}
else if {state is FailPage)     {return FailPage;}

to this:

switch (state){
case LoadingPage:   {return LoadingPage;}
case SuccessPage:   {return SuccessPage;}
case FailPage:      {return FailPage;}
}

It didn't work, what worked for me is making the state as a string, like this:

switch (state.toString()){
    case 'LoadingPage':      {return LoadingPage;}
    case 'SuccessPage':      {return SuccessPage;}
    case 'FailPage':         {return FailPage;}
    }

It works though, but it's a short time solution, like if I had to edit something, it gonna be so hard to change everything (since it's a string)..

Restriction answered 23/8, 2022 at 23:50 Comment(1)
Hi, I have added a solution somewhat similar to switch. You can use map to handle all cases or maybeMap() to only handle the case you need.Chemarin
D
3

2023 - switch with Dart 3.0 Pattern matching

Overview code

class Dog {
  Dog({required this.name});
  final String name;
}

class Cat {
  Cat({required this.name});
  final String name;
}

String checkType(dynamic v) {
  String type;

  switch (v) {
    case Dog(:final name):
      type = 'dog, $name';
    case Cat cat:
      type = 'cat, ${cat.name}';
    case int:
      type = 'int';
    case (String name, String age):
      type = 'Record ($name, $age)';
    case {'user': {'name': final String name, 'age': final int age}}:
      type = 'User Json $name, $age';
    default:
      type = 'unknown';
  }

  return type;
}

Object Destructing

switch (v) {
  case Dog(name:final name):

// or You can skip name if use same name.

switch (v) {
  case Dog(:final name):

⚠️ Docs: They are refuted if the value doesn’t have the same type.

You should use correct type to destructing object.

Just use final or var to indicate data type so you always use same type of object field.

return switch (v) {
  Dog(:String age) => 'dog, $age', // Compile error 'The getter 'age' isn't defined for the type 'Dog'.'
  Dog(name: String otherName) => 'dog, $otherName', // OK, Success to match
  Dog(:int name) => 'dog, $name', // Fail to match
  Dog(:String name) => 'dog, $name', // Success to match, But can't to be reached.

Just assign to variable (can be final with prefix final)

case Cat cat:
  type = 'cat, ${cat.name}';

or

case final Cat cat:
  type = 'cat, ${cat.name}';

Record Destructing

case (String name, String age):
  type = 'Record ($name, $age)';

Map Destructing

case {'user': {'name': final String name, 'age': final int age}}:
  type = 'User Json $name, $age';

You can also use switch expression.

String checkType(dynamic v) {
  return switch (v) {
    Dog(:final name) => 'dog, $name',
    Cat cat => 'cat, ${cat.name}',
    int => 'int',
    (String name, String age) => 'Record ($name, $age)',
    {'user': {'name': final String name, 'age': final int age}} =>
      'User Json $name, $age',
    _ => 'unknown',
  };
}

You can check more information in the Dart docs

Damondamour answered 16/10, 2023 at 5:47 Comment(0)
A
0

Do this:

switch (state.runtimeType){
case LoadingPage:   {return LoadingPage;}
case SuccessPage:   {return SuccessPage;}
case FailPage:      {return FailPage;}
}
Apheliotropic answered 14/12, 2022 at 16:34 Comment(1)
You should not use runtimeType, It changes based on compiler options. Also it doesn't work properly with subclasses and generics. github.com/felangel/bloc/issues/1595Luffa
V
0

You are looking for the switch expression. The Dart team just added this in V3 of Dart.

enum PageState { LoadingPage, SuccessPage, FailPage }

void main() {
  final state = PageState.SuccessPage;
  final text = switch (state) {
    PageState.LoadingPage => 'LoadingPage',
    PageState.SuccessPage => 'SuccessPage',
    PageState.FailPage => 'FailPage',
    _ => 'None'
  };
  print(text);
}

For more details, you can read here

Vexation answered 12/5, 2023 at 4:15 Comment(0)
C
-1

There is a package named freezed for this exact solution where we do not use switch rather map and/or maybeMap.

@freezed
class MemberState with _$MemberState {
  factory MemberState.initial() = _MemberStateInitial;
  factory MemberState.loading() = _MemberStateLoading;
  factory MemberState.loadSuccess({required MemberDetail detail}) =
      _MemberStateLoadSuccess;
  factory MemberState.loadFailure({required AppFailure failure}) =
      _MemberStateLoadFailure;
}

Usage:

  @override
  Widget build(BuildContext context) {
    return BlocBuilder<MemberBloc, MemberState>(
      builder: (context, state) {
        return const Scaffold(
          body: state.map(
              initial: initial,
              loading: loading,
              loadSuccess: loadSuccess,
              loadFailure: loadFailure),
        );
      },
    );
  }

Of course, I use it with BLoCs but the underlying concept is the same. You can use it in any way you like. And, the best thing is it is all generated automatically. So, you wouldn't have to write the code yourself.

Chemarin answered 24/8, 2022 at 2:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.