Flutter中自定义@required反向注解的技术需求问询
@required Annotation in Dart Got it, let's tackle this problem. You want a custom annotation that does the opposite of @required—warning developers when they pass a parameter that's supposed to be ignored, instead of warning when it's missing. This makes perfect sense for your Usecase abstract class, where some implementations need parameters and others don't. Here's how to build it:
Step 1: Define the @Unrequired Annotation
First, create a simple annotation class. Annotations in Dart are just classes with a const constructor:
/// Marks a parameter that should NOT be passed to a method. /// Passing this parameter will trigger a lint warning, as it will be ignored. class Unrequired { const Unrequired(); }
This is the marker we'll use on parameters that are meant to be left out.
Step 2: Create a Custom Lint Rule (The Critical Part)
Dart's default analyzer won't recognize our new annotation out of the box. We need to write a custom lint rule to check for cases where an @Unrequired parameter is being passed.
Set Up the Lint Rule
If you don't already have a custom lint setup, create a small analyzer plugin project or add the rule directly to your project's analysis setup. Here's the core logic for the rule:
import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:linter/src/linter.dart'; class UnrequiredParameterRule extends DartLintRule { UnrequiredParameterRule() : super( code: const LintCode( name: 'unrequired_parameter', problemMessage: 'This parameter is marked as @Unrequired and will be ignored.', correctionMessage: 'Remove this redundant parameter.', errorSeverity: ErrorSeverity.WARNING, ), ); @override void registerNodeProcessors( NodeLintRegistry registry, LinterContext context, ) { // Listen for method invocations (like calling your Usecase's `call` method) registry.addMethodInvocation(this, _checkUnrequiredParams); } void _checkUnrequiredParams(MethodInvocation node) { // Get the method element being called final methodElement = node.methodName.staticElement as MethodElement?; if (methodElement == null) return; // Loop through all named arguments passed in the invocation for (final namedArg in node.argumentList.namedArguments) { final paramName = namedArg.name.label.name; // Find the corresponding parameter in the method definition final paramElement = methodElement.parameters.firstWhereOrNull( (p) => p.name == paramName, ); if (paramElement == null) continue; // Check if the parameter has our @Unrequired annotation final hasUnrequiredAnnotation = paramElement.metadata.any( (meta) => meta.type.element?.name == 'Unrequired', ); // If it does, report a lint warning if (hasUnrequiredAnnotation) { reportLintForToken(namedArg.name.label); } } } }
Integrate the Rule into Your Project
Add the rule to your analysis_options.yaml so the analyzer picks it up:
linter: rules: - unrequired_parameter # Add your custom rule here # If your rule is in a local plugin, include the plugin path: analyzer: plugins: - custom_lints # Replace with your plugin name/path
Step 3: Use the Annotation in Your Usecase Implementations
Now you can use @Unrequired on parameters that should be ignored. For example:
Base Usecase Class
First, update your base class to make the parameter nullable (since some implementations won't use it):
abstract class Usecase<F extends Failure, S, Params extends Tuple> { Future<Either<F, S>> call({Params? param}); }
Implementation Without Parameters
Mark the param as @Unrequired to warn developers if they try to pass it:
class FetchHomeDataUsecase extends Usecase<Failure, HomeData, Tuple0> { @override Future<Either<Failure, HomeData>> call({@Unrequired() Tuple0? param}) async { // We ignore `param` here since this usecase doesn't need it final data = await _repository.getHomeData(); return Right(data); } }
Now, if someone tries to call FetchHomeDataUsecase()(param: Tuple0()), their IDE will show a warning saying "This parameter is marked as @Unrequired and will be ignored."
Implementation With Parameters
For usecases that do need parameters, keep using Dart's built-in required keyword (the modern replacement for @required):
class FetchUserUsecase extends Usecase<Failure, User, Tuple1<String>> { @override Future<Either<Failure, User>> call({required Tuple1<String> param}) async { final user = await _repository.getUser(param.value); return Right(user); } }
This will warn developers if they forget to pass the param as expected.
Key Notes
- The custom lint rule can be adjusted to target only your
Usecaseclass'scallmethod if you want to limit its scope (just add a check for the method's enclosing class type in the rule logic). - Make sure your team has the custom lint rule set up locally so everyone sees the same warnings.
内容的提问来源于stack exchange,提问作者mohammad

