To be clear, this is Not a duplicate of this question. Obviously, I can use the nameof
operator to get the name of a variable or a parameter; I know that. But is there a way I can get the original name of a variable that's passed to a method? Currently, I have to do it like this:
static void Foo(string someVariable, string variableName)
{
if (!FulfilsCondition(someVariable))
Console.WriteLine($"{variableName} is bad!");
// More code
}
And I call it like this:
string bar = string.Empty;
Foo(bar, nameof(bar)); // Or...
//Foo(bar, "bar");
But I'm looking for a way to avoid repeatedly providing the name of the variable and, instead, use something like:
Foo(bar);
Where Foo
, in this case, would be:
static void Foo(string someVariable)
{
string variableName = GetOriginalVariableName(someVariable);
// Is this possible? ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
if (!FulfilsCondition(someVariable))
Console.WriteLine($"{variableName} is bad!");
// More code
}
Is something like this achievable in .NET?
Update:
I didn't think of the possibility that what gets passed to Foo
could be an expression and not a variable as others have suggested in the comments. Thinking about it now, it doesn't seem to be possible to achieve what _unless I can (somehow) guarantee that there will always be a variable? Sounds like a long shot, TBH, but maybe there's a solution there.
Update #2:
People asked about what I'm actually trying to achieve. Well, it's very similar to the first method above but here's the actual method I'm using if that's going to help:
static bool ExceedsLimit(string s, int maxLength, string variableName,
out string errorMessage)
{
if (s.Length > maxLength)
{
errorMessage = $"'{variableName}' must be {maxLength} characters at most.";
return true;
}
errorMessage = null;
return false;
}
And I'm using it in something like this:
static bool TestMethod(out bool failReason)
{
if (ExceedsLimit(obj.Prop1, 100, nameof(obj.Prop1), out failReason)) return false;
if (ExceedsLimit(obj.Prop2, 50, nameof(obj.Prop2), out failReason)) return false;
if (ExceedsLimit(obj.Prop3, 80, nameof(obj.Prop3), out failReason)) return false;
// ...
}
But I'm looking for a way to avoid repeatedly providing the name of the variable.
What you are looking for is going to work much slower than passing param name additionally.
But workarounds are possible. I went crazy about your problem and found out something. It has restrictions. Such as dealing with local variables only. (But can be extended to solve other cases). And it needs pdb files and ildasm tool. (It seemed to be the simplest way to get IL, but maybe it can be obtained with framework functionality). And it's terribly slow. But it works) Just call ParamNameHelper.GetOriginalVariableName(string paramName).
Output: s is passed as strArg
No, It's not possible because a method has no way of knowing what the names of it's arguments where. Aka
Foo
has no way of knowing if it was called asFoo(bar)
orFoo(baz)
. What you cold do is useCallerMemberName
to get the name of the method it was called from. For example:Would print:
You can use
Mono.Cecil
for that purpose. You also needMonoCecilReader
and some other types from this answer and.pdb
files to get local variables' names.Ammend
MethodDefinitionExtensions
withCreate
ResolvedArgument
class:Then create static class
VariableHelper
with methods:Where
GetParameter
is:and
GetPassedValue
is:Extension methods for
Instruction
are:Usage:
Gives:
The above solution is mostly a demonstration of possibility. It works much slower than simply passing a variable's name.