Roslyn: nameof doesn't work with parameters or generic arguments at a method attribute level

Created on 27 Aug 2015  路  10Comments  路  Source: dotnet/roslyn

Given the following attribute:

[AttributeUsage(AttributeTargets.All)]
public class MyAttribute : Attribute
{
    public MyAttribute(string value)
    {
        Value = value;
    }

    public string Value { get; }
}

The following is possible inside of a class/struct declaration:

[MyAttribute(nameof(myField))]
private int myField;

I would expect all of the following to also be possible:

[MyAttribute(nameof(TResult) + nameof(myParameter))]
[return: MyAttribute(nameof(TResult) + nameof(myParameter))]
public TResult DoSomethingGeneric<TResult>([MyAttribute(nameof(TResult) + nameof(myParameter))] int myParameter)
{
    return default(TResult);
}

However it appears that none of these nameofs work, I would consider the generic argument and myParameter to be in the available scope for all of these.

The use case for this is with WebApi and the RouteAttribute where parameters may be specified as part of the route, e.g:

[HttpPost]
[Route("{id:int}/something")]
public void DoSomething(int id)
{    
}

Allowing it to be replaced with the following:

[HttpPost]
[Route("{" + nameof(id) + ":int}/something")]
public void DoSomething(int id)
{    
}

Seems very much in the use-case of the nameof operator.

0 - Backlog Area-Language Design Feature Request

Most helpful comment

Isn't one of the benefits of nameof that it removes the potential error of renaming something and the related string not being changed respectively? For that reason I would personally prefer the use of nameof in the attribute.

What exactly does ReSharper do with string.Format? I'm not quite sure what you are referring to.

All 10 comments

I am not against this at all, but can't you achieve the same already by inspecting the method signature via reflection? You are going to use reflection anyway.

Frankly speaking I prefer this:

[HttpPost]
[Route("{id:int}/something")]
public void DoSomething(int id)
{    
}

...to this:

[HttpPost]
[Route("{" + nameof(id) + ":int}/something")]
public void DoSomething(int id)
{    
}

Have you seen what ReSharper does with string.Format()?

image

You can achieve something similar with Roslyn for the scenario above and avoid the unnecessary string arithmetic.

Isn't one of the benefits of nameof that it removes the potential error of renaming something and the related string not being changed respectively? For that reason I would personally prefer the use of nameof in the attribute.

What exactly does ReSharper do with string.Format? I'm not quite sure what you are referring to.

Yes, but nameof is most beneficial in places where reflection is not readily available - for example method bodies. If scenario revolves around metadata that is available via reflection, then a lot is possible even without nameof.

ReSharper will warn you if a template is not consistent with the arguments passed. I did not have a chance to use ReSharper 9 a lot, but I am pretty sure that interpolation will get parameter name validation. Same should be possible with Roslyn.

Don't take my comments as an opposition, I believe nameof should be enabled in custom attributes. It's a good suggestion.

These names are _not_ in scope today, so this is a feature request.

I was also surprised to find out that this doesn't work. In particular, when you consider the following example, the current behavior is very inconsistent:

``` C#
[Category(nameof(f))] // Ok
[Description(nameof(T))] // Ok
class X
{
private int f;

// error CS0103: The name 'U' does not exist in the current context
[Category(nameof(U))] 
// error CS0103: The name 'q' does not exist in the current context
[Description(nameof(q))]  
private void M<U>(int q) { }

}
```

Nice find @axel-habermaier, I guess the nameof({privateField}) is supported because the following is also supported?

[Category(myConst)]
class X
{
    private const string myConst = "Test";
}

However it seems very inconsistent to allow the use of nameof like this at a class level attribute but not a method level attribute and just plain wrong to expose the name of private fields but not public parameters/method type arguments.

@gafter I am assuming there is an internal C# 6 language specification? Otherwise how else could it be determine this is a feature request instead of a bug? It's very hard to know what should/shouldn't be supported without a public specification.

@Lukazoid The C# 6 spec is being prepared as we speak, though the feature was extensively discussed over on codeplex.

@axel-habermaier The introduction of nameof certainly exposes strange edge cases of scoping that never used to arise much in practice. Unfortunately changing them even slightly to make these cases involving nameof more intuitive can break existing code.

We are now taking language feature discussion on https://github.com/dotnet/csharplang for C# specific issues, https://github.com/dotnet/vblang for VB-specific features, and https://github.com/dotnet/csharplang for features that affect both languages.

See also https://github.com/dotnet/roslyn/issues/18002 for a general discussion of closing and/or moving language issues out of this repo.

This seems to be documented here but does not work for me: https://github.com/dotnet/csharplang/blob/master/meetings/2019/LDM-2019-05-15.md#nullness-dependencies-between-inputs-and-outputs

Was this page helpful?
0 / 5 - 0 ratings