Test code included at the bottom of this report.
Currently if method with a parameter marked as CallerMemberNameAttribute is called from a local method it will receive local method's name instead of actual type member's name.
This behavior might lead to subtle bugs because lambda expressions and anonymous methods behave differently. Therefore if I replace an anonymous method or a lambda expression with a local method this change will alter the behavior of my program in a way which can be hard to notice.
Two of the following properties raise the NotifyPropertyChanged event with string 'Property' for the changed property's name and one of them with 'local' string.
public int Property
{
set
{
Action anonymous = delegate { OnPropertyChanged(); };
SetAndRaisePropertyChanged(SetBackingField, anonymous);
}
}
public int Property
{
set
{
Action lambda = () => OnPropertyChanged();
SetAndRaisePropertyChanged(SetBackingField, lambda);
}
}
public int Property
{
set
{
void local() => OnPropertyChanged();
SetAndRaisePropertyChanged(SetBackingField, local);
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberNameAttribute] string propertyName = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
Is this behavior intended or not? If it is not intended how the CallerMemberNameAttribute should behave with local methods?
My guess is that this is intended. Anonymous functions (lambdas and anonymous methods) don't have names (that's why they're called "anonymous"), so there is nothing the CallerMemberName parameter could receive.
But local functions do have names, so it makes sense to me that CallerMemberName receives a local function's name.
Well, constructors pass ".ctor" string since they don't have correct name. Indexers pass "Item". Destructors pass "Finalize". Operator overloads pass things like "op_UnaryPlus".
So it doesn't look like having 'meaningful' name is required for the attribute to work.
I guess if passing name of a closure was intended lambdas and anonymous methods coulds as well pass ".labmda" or ".anonymous" or the name that compiler generated for them.
I think those are all useful names, they tell you something useful and are standardized (to lesser or greater degrees).
On the other hand, .lambda (or anything similar) would be inventing a completely new name and e. g. <>c.<M>b__0_0 would be surfacing implementation details. In any case, any change for anonymous functions would be a breaking change now.
I'm not suggesting changing lambdas/anonymous behavior. I do think that changing anonymous method to local shouldn't be a breaking change to your program, though. Currently it is.
What useful information can you get from ".ctor" or "op_Implicit" or "Item" if you have more than one constructor, indexer or implicit conversion operator?
Local functions are not "members" and therefore should probably not be treated as having a "member name".
@gafter
What would the expected output be? from applying <CallerMemberNameAttribute> on a Local Function. Would it be a null string or an empty string?
So it can be add as another test case, in the unit test.
@AdamSpeight2008 I think it should get the name of enclosing member, e.g. name of the member function in which the local function is defined and called.