1

I am I am using C# 7+, and I am aware of the [CallerMemberName] attribute, but what I am looking for is an attribute that would get me the name of an argument.

Use case: Checking for null, even with the ?? and ? null operators, can be a bit tedious with the condition checks and throwing the proper exceptions with the proper values. For a few months now I've been using a solution inspired by some article I read and that could be described as an "argument validation builder". It would be used something like this:

public class MyClass
{
    public void DoTheThing(IFoo foo, ICollection<IBar> bars, string specialText)
    {
        new ArgumentValidator()
            .NotNull(foo, nameof(foo))
            .NotNullOrEmpty(bars, nameof(bars))
            .NotNullOrEmpty(specialText, nameof(specialText));

        ...rest of function
    }
}

If, for example, foo was null, then ArgumentValidator.NotNull(...) would throw a new ArgumentNullException with the parameter name "foo". This approach makes argument checking a bit more concise, and that's pretty much the only reason I'm doing this.

It would be really nice if I didn't have to specify nameof(...) every single time. That is, I'd like to be able to do this:

        new ArgumentValidator()
            .NotNull(foo)
            .NotNullOrEmpty(bars)
            .NotNullOrEmpty(specialText);

In order to do that though, I would need to figure how to make the NotNull(...) and other functions figure out the name of the argument.

I've tried making a parameter-based attribute, I've tried looking at Environment.StackTrace (not thrilled about trying to parse that nor about the performance implications), I've looked at StackFrame, I've looked at getting type info about the class -> method info -> parameter info and the custom attributes, and I still haven't found a way forward.

I'd like to make an attribute similar to [CallerMemberName], but this attribute would extract the name of the argument that was used to call the function, assign it to the decorated parameter, and would performs quickly (in other words, I want to avoid stack trace stuff if possible, especially since I'm using these checks a lot).

This is where I'm at:

[AttributeUsage( AttributeTargets.Parameter )]
class ArgumentNameAttribute : Attribute
{
    public string SomeProperty { get; set; }
}

class Program
{
    static void NotNull<T>( T argument, [ArgumentNameAttribute] string argumentName )
    {
        //how to get at the argumentName?
    }

    static void DoTheThing( string thing )
    {
        NotNull( thing );
        Console.WriteLine( "hello world" );
    }

    static void Main( string[] args )
    {
        DoTheThing( "12345" );
    }
}

Alternately, I'll accept another solution that makes argument checking concise and expressive.

Ideas?

John Cox
  • 339
  • 1
  • 3
  • 15
  • If you're using C# 8, you might be able to use [nullable reference types](https://learn.microsoft.com/en-us/dotnet/csharp/nullable-references) to address these concerns and avoid all of this validation code altogether. – itsme86 Oct 10 '19 at 20:04
  • 1
    I don't think Reflection is the answer, because you need the name of the thing being passed as a parameter from the calling code. Reflection will help you get around, but not reverse engineer the calling code. Aspect oriented programming would allow you to weave this in at compile time. – Richardissimo Oct 10 '19 at 20:39
  • > Aspect oriented programming would allow you to weave this in at compile time You have my attention. Please explain – John Cox Oct 10 '19 at 21:31
  • Slapping "aop" into your favorite search engine will be much faster then waiting here for comments, it yields results like this: https://stackoverflow.com/questions/633710/what-is-the-best-implementation-for-aop-in-net. But beware this question is old, in 10 years a lot of things emerge. – thehennyy Oct 11 '19 at 06:41
  • In IL, arguments do not actually have names, they are only numbered -- argument names are strictly a compile-time construct. At runtime, argument names for diagnostics are tacked on through the debugging info, if present. This is why `nameof` is really the only practical way to get at them; reflection won't help you either. The kind of attribute you propose cannot be written by application writers as it needs compiler support; it'd have to be implemented as part of the language -- and it's actually [been proposed](https://github.com/dotnet/csharplang/issues/287), but not implemented (yet). – Jeroen Mostert Oct 11 '19 at 10:30

1 Answers1

0

No one has created an answer yet, but comments have mentioned alternatives:

  • Aspect Oriented Programming (AOP)
  • Use C# 8's nullable reference type syntax

While not answering the specific question, these did answer the general intent of a cleaner way to handle null types. Considering my question answered.

John Cox
  • 339
  • 1
  • 3
  • 15