-
Notifications
You must be signed in to change notification settings - Fork 272
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Relax AV1555 so that named parameters are permitted when invoking external libraries #276
Comments
I think I've seen a matching Resharper/Rider setting for named lambda parameters, would be nice to use matching terminology so it can be automated. I just got back from vacation, will take a look in the next few days. |
I also like this heuristic. https://stackoverflow.com/a/443507/253961 |
The Resharper settings for controlling this are documented here. For lambda's, here's how to set it up: Which results in the following addition to the <s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/ARGUMENTS_ANONYMOUS_FUNCTION/@EntryValue">Named</s:String> I've tried this setting out on a codebase, but the results are pretty disappointing because it affects many LINQ methods. Examples (before): _parameterReaders.FirstOrDefault(reader => reader.CanRead(parameterName));
propertySelectors.Select(selector => CreatePropertyAssignment(selector, lambdaScope, context));
Values.All(selectors => selectors.IsEmpty);
expression.Elements.OrderBy(element => element.Relationship.PublicName);
AppDomain.CurrentDomain.GetAssemblies().Any(assembly => ...
currentState.FieldsMatched.Sum(field => field.PublicName.Length + 1); Examples (after): _parameterReaders.FirstOrDefault(predicate: reader => reader.CanRead(parameterName));
propertySelectors.Select(selector: selector => CreatePropertyAssignment(selector, lambdaScope, context))
Values.All(predicate: selectors => selectors.IsEmpty);
expression.Elements.OrderBy(keySelector: element => element.Relationship.PublicName);
AppDomain.CurrentDomain.GetAssemblies().Any(predicate: assembly => ...
currentState.FieldsMatched.Sum(selector: field => field.PublicName.Length + 1); In my opinion, turning this setting on isn't worth the extra noise it introduces. This makes me wonder how common it is for a method to take multiple lambda arguments? Aside from Assuming this happens only rarely, a Resharper suppression preserves the names while still allowing to auto-format the full solution: private IDictionary<string, object?> Demo(IDictionary<string, ParameterNode> parametersByName)
{
// ReSharper disable ArgumentsStyleAnonymousFunction
return parametersByName.Values.ToDictionary(
keySelector: parameter => parameter.Name, elementSelector: parameter => parameter.Value);
// ReSharper restore ArgumentsStyleAnonymousFunction
} Either way, I think the coding guidelines should dictate a non-ambiguous style instead of relaxing the current one by allowing (but not requiring) named arguments for lambdas. That would result in multiple styles within the codebase (depending on who wrote the code), which is what we're trying to prevent. A simpler solution is to use a local function to improve readability (two variants, where the function name clarifies the lambda purpose): private IDictionary<string, object?> Demo(IDictionary<string, ParameterNode> parametersByName)
{
return parametersByName.Values.ToDictionary(SelectKey, GetElementSelector());
static string SelectKey(ParameterNode parameter)
{
return parameter.Name;
}
static Func<ParameterNode, object?> GetElementSelector()
{
return parameter => parameter.Value;
}
} CSharpGuidelinesAnalyzer could be changed to require named lambda arguments when the called method declares more than one lambda parameter (and forbid using a named lambda argument when there's only one). I would welcome more use cases and feedback from users before changing this rule, so we can properly define it. |
Thanks for the extensive analysis.
I don't agree with that. Although I appreciate a certain amount of consistency, I don't want to be dogmatic about it. Just like the use of Suppressing AV1555 for those particular cases is one way of allowing that, but I'm my experience, all those pragmas can make the code quite noisy. In those cases, I tend to disable the rule entirely. |
Surely the guidelines are not hard rules, if that's what you mean. It's usually fine to deviate when there's good motivation. I just don't get your motivation on why using named parameters is more readable in your opinion. And when you consider it good practice to use named parameters. And how frequently it applies in a codebase. Can you answer these? Personally, I would write the code as: builder.Services.AddLogging(loggingBuilder =>
{
if (!string.IsNullOrWhiteSpace(connectionString))
{
loggingBuilder.AddApplicationInsights(
telemetryConfiguration => telemetryConfiguration.ConnectionString = connectionString,
applicationInsightsLoggerOptions => { }
);
}
}); which matches existing guidelines and is readable enough for me. It also resonates with the general guidance to prefer helpful (as opposed to meaningless) names for identifiers, such as types, members, variables, etc. |
That isn't bad at all. And with that I mean: that's a great alternative that would address my concerns. |
The following use of named parameters when invoking
AddApplicationInsights
should be allowed by AV1555Whether that external library is a package build by the same developer isn't relevant.
See also discussion bkoelman/CSharpGuidelinesAnalyzer#145
The text was updated successfully, but these errors were encountered: