dotnet / csharplang

The official repo for the design of the C# programming language
11.49k stars 1.02k forks source link

[Proposal]: Allow nameof(method parameter) outside the method. #4413

Open Youssef1313 opened 3 years ago

Youssef1313 commented 3 years ago

Allow nameof(method_parameter_name)

Summary

Currently, there is no way to use a parameter name outside the method without hardcoding it.

Motivation

Extending nameof capabilities and allowing it to be used in more contexts. Similar to: https://github.com/dotnet/csharplang/issues/4384, and extends https://github.com/dotnet/csharplang/issues/373 (not a dupe of it)

Detailed design

While #373 suggests allowing nameof for parameter names in attributes applied to the method, this proposal is a suggestion to generalize it to be allowed outside the method context. A real-world example that can benefit from this:

https://github.com/dotnet/roslyn-analyzers/blob/b76ff2f/src/Microsoft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/DiagnosticDescriptorCreationAnalyzer.cs#L29-L35

public class C
{
    public void M()
    {
        var x = nameof(M.s); // Same as var x = "s";
        var x = nameof(M.y); // Compile error.
    }

    public void M(object s) { }
}

Drawbacks

Alternatives

Unresolved questions

Design meetings

YairHalberstadt commented 3 years ago

Would you be able to access members of the parameter as well? E.g. in your example nameof(M.s.ToString)?

Youssef1313 commented 3 years ago

Would you be able to access members of the parameter as well? E.g. in your example nameof(M.s.ToString)?

Probably depends on the ease of implementation. There is already a cleaner way to do that (nameof(WhateverTypeTheArgumentIs.ToString)).

HaloFour commented 3 years ago

The syntax of using member access to reference a parameter of a method feels really weird here, as does the name resolution (although you could argue that the latter is already "broken" by method group resolution). It gets much weirder if you can dot into the members of the parameter type, especially if there are overloads of that method that could have parameters of the same name but of different types.

What are the use cases where you'd want to take the name of a method parameter in a separate method body?

Youssef1313 commented 3 years ago

The syntax of using member access to reference a parameter of a method feels really weird here, as does the name resolution (although you could argue that the latter is already "broken" by method group resolution). It gets much weirder if you can dot into the members of the parameter type, especially if there are overloads of that method that could have parameters of the same name but of different types.

What are the use cases where you'd want to take the name of a method parameter in a separate method body?

The use case that come to mind is mostly for analyzers, such as the example provided.


It gets much weirder if you can dot into the members of the parameter type, especially if there are overloads of that method that could have parameters of the same name but of different types.

That's correct. In that case I think accessing into the members of the parameter should be completely disallowed.


The syntax of using member access to reference a parameter of a method feels really weird here

Could we consider another token other than the DotToken?

ashmind commented 3 years ago

What are the use cases where you'd want to take the name of a method parameter in a separate method body?

One use case is to register specific parameter value during dependency injection registration. It's a bit of an edge case, but I still run into it periodically. Something like this (artificial):

builder.RegisterType<Processor>()
       .As<IProcessor>()
       .WithParameter("timeout", config.Timeout);

Note that it requires nameof access to constructor parameters though.

TahirAhmadov commented 2 years ago

Will this support parameters of methods in other types?

const string s = nameof(My.Namespace.Class.Method.parameter);
333fred commented 2 years ago

Currently, there is no proposal for adding such semantics.

Jawvig commented 2 years ago

Another example of usage would be attributes. For instance, in the Open API & Azure Functions attributes OpenApiParameterAttribute and HttpTriggerAttribute respectively. For example:

/*...*/
[OpenApiParameter(name: nameof(FuncClass.SomeFunction.someParam), In = ParameterLocation.Path /*, ... */)]
/*...*/
public async Task<IAsyncResult> SomeFunction(
    [HttpTrigger(/*...*/ Route=$"abc/{{{nameof(FuncClass.SomeFunction.someParam}}}/abc")] HttpRequest request,
    string  someParam)
{
   /* ... */
}

Even better would be if some of the context could be inferred so that the class or method name don't need to be applied based on the target of the attribute.

Jawvig commented 2 years ago

Never mind, I should have read the proposal in more detail as the use in attributes is in https://github.com/dotnet/csharplang/issues/373