3

[CallerLineNumber] is a great language feature. But I'm using it to automatically order class properties as their declaration order. However when the user calls the function or constructor with this parameter, the user is able to feed a value to it, which completely beats the purpose of auto-generation. Currently, I have to name this parameter something like _doNotSet, as a hint to the caller to not set this parameter.

How can I force it to be read only, or even better, hide it from the function signature?

The other thought I had was to mark the parameter as [Obsolete] so by using it the compiler will warn. Unfortunately, ObsoleteAttribute is not targeted for parameter, so I can't mark a parameter as so.

Community
  • 1
  • 1
KFL
  • 17,162
  • 17
  • 65
  • 89
  • This could be an issue if it was actually related to a "user", but in reality this minute issue is only related to potential coders and nothing a doc comment won't handle. – TyCobb Jun 21 '14 at 04:36
  • 2
    This piggy-backs onto the compiler support for optional arguments, a hard requirement to let the compiler generate the value. There is no possible syntax to make you happy, no lack of /// options to educate the user. – Hans Passant Jun 21 '14 at 09:17

2 Answers2

2

I am surprised that the compiler doesn't override the value passed in by the calling function. Anyway, accepting that unfortunate behavior I don't think there is going to be anything you can do to guarantee no one will break that.

As far as I am aware, the closest you could come is what you have done. Name it something like _doNotSet but I would suggest something like _settingThisBreaksTheTool. Depending on the audience of the code this may be enough to satisfy your needs.

Edit: This link shows how to determine if a value was supplied or not, unfortunately none of the tactics supplied there are going to work for you. Basically they suggest using a known unlikely value (impossible in your case since you won't know the line number or you wouldn't care). Or don't use default values and overload the function. But the [CallerLineNumber] attribute needs the parameter to be optional to work. Bugger.

Come on Microsoft... Why

This goes into how .Net implements default values for optional parameters. When you specify that a parameter is optional on a function, and call that function with no value something quite special happens during compilation. The code which does not have a value for that parameter is replaced with code which does have a value, the default value.

I read a few blog posts on this awhile ago, this was the simplest to understand the basics.

I may be making a few jumps here but my guess is that the [CallerLineNumber] attribute signals the compiler to use a different value, namely the line number. But the compiler won't even go through the process to inject values since there was a value in the first place.

Probably Microsoft would like the [CallerLineNumber] to override the value passed into the function, but the side affect of piggybacking default values probably caused them to not be able to support that. I will be interesting to see if the Roslyn project brings some enhancements with that function.

TheNorthWes
  • 2,661
  • 19
  • 35
0

You can create an interface like ICallerLineNumberPlaceholder.

public Task<TResult> ExecuteWithArgs<TResult, TParam>(Func<IDBLambdaEngine, TResult> queryExpression, TParam param, ICallerLineNumberPlaceholder placeholder = default, [CallerLineNumber] int callerLineNumber = 0) where TResult : new()
{
    return InternalExecute<TResult, TParam>(callerLineNumber, param);
}
thatguy
  • 21,059
  • 6
  • 30
  • 40
Nothing
  • 1
  • 2