1

I have this

public static class Parameters
{
    public static void Required<T>(this T parameter, string paramName) where T : class
    {
        if (parameter == null)
        {
            throw new ArgumentNullException(paramName);
        }

        // ...
    }
}

And I use it like:

Parameters.Required(settings, nameof(settings));

Is it possible to get rid of the second parameter and somehow get the original parameter name, from within the Required method? No, right?

hyankov
  • 4,049
  • 1
  • 29
  • 46
  • 3
    @Liam Disagree, OP isn't trying to get the name of the type. OP wants the name of the variable being passed in. –  Mar 22 '19 at 13:36
  • 2
    In this example I don't see why you would throw the exception with `paramName` when `parameter` is `null`and not `paramName`? – IDarkCoder Mar 22 '19 at 13:36
  • No, you need `nameof`. `nameof` is a compile-time thing, which tells the compiler to substitute the string literal "settings". If you don't do this at compile-time, there's no way to do it a run-time. – canton7 Mar 22 '19 at 13:36
  • I *suppose* it could be accomplished using expression trees, but it would require additional alterations to the method call. –  Mar 22 '19 at 13:37
  • @IDarkCoder because at this point the name of `parameter` is "parameter" and I want the original name. Hence, my question. – hyankov Mar 22 '19 at 13:38
  • 3
    Compiling expressions to do something as cheap as a null-check seems like overkill – canton7 Mar 22 '19 at 13:38
  • 2
    Impossible, most likely. What would happen for `Parameters.Required(obj.Something ? (object) obj.SomethingElse : obj.EntirelyDifferent)`? Probably unrealistic, but it's something you have to keep in mind, is possible. – Caramiriel Mar 22 '19 at 13:40
  • 3
    @canton7 I wholeheartedly agree. Dr. Malcolm: "Yeah, but your [computer] scientists were so preoccupied with whether or not they could, they didn't stop to think if they should." –  Mar 22 '19 at 13:42
  • Unless `Parameters.Required` is going to do something interesting other than throw the exception, using it is counterproductive -- you're not only giving the compiler and the JIT a harder workout, you're also complicating stack traces. If your method does have special logic, consider something of the form `if (param == null) throw HelperClass.ArgumentNull(nameof(param))`, with `ArgumentNull(string name) { myCustomLogic(); return new ArgumentNullException(name); }`. This pattern is used in the framework itself in a few places (to localize exception strings, mostly). – Jeroen Mostert Mar 22 '19 at 13:46
  • @JeroenMostert the whole idea is I want it to be a one-liner with a single parameter. Come on, nobody has mentioned `contracts` so far, I am almost disappointed. – hyankov Mar 22 '19 at 13:48
  • Contracts are *so* last year – canton7 Mar 22 '19 at 13:52
  • 1
    Yeah, that's not going to happen, sorry. Not at a reasonable cost, anyway -- as others have pointed out, expression trees would work, but these "one-liners" would be prohibitively expensive, especially if you applied them throughout your entire code base. Most editors have support for inserting null checks with one (or two) presses of a button. Or wait for C# 8's nullable reference types so you can get rid of a lot of checks... If you want to go the Code Contracts route, you certainly can -- just make your own IL rewriter or Roslyn extension, easy as pie. :-P – Jeroen Mostert Mar 22 '19 at 13:53
  • @HristoYankov Code Contracts are dead. https://github.com/dotnet/docs/issues/6361 –  Mar 22 '19 at 13:53
  • 1
    I don't believe that nullable reference types will get rid of the need for null-checks - nothing fundamentally will stop a `string` from containing `null`. – canton7 Mar 22 '19 at 13:59
  • nullable reference types won't replace null-checks at all. That's not what they are about. – Lasse V. Karlsen Mar 22 '19 at 14:02
  • NRTs won't eliminate null checks altogether (you will always need them around the public edges, and when you've made a conscious choice to introduce `null`), but they can certainly help reduce the need for them within a code base. Technically, of course, you can already just not do null checks if you like, but diagnosing the resulting NREs is painful. – Jeroen Mostert Mar 22 '19 at 14:04
  • Possible duplicate of [get name of a variable or parameter](https://stackoverflow.com/questions/9801624/get-name-of-a-variable-or-parameter) – meJustAndrew Mar 22 '19 at 14:28

1 Answers1

2

You could make the Requred-function accepting a Expression. And from the expression you can read out the name of the member name. It's descriped here.

    public static void Required<T>(Expression<Func<T>> parameter) where T : class
    {
        if (parameter.Compile().Invoke() == null)
        {
            var caller = ((MemberExpression)parameter.Body).Member.Name;
            throw new ArgumentNullException(caller);
        }

        // ...
    }

and call it like this:

Parameters.Required(() => settings);
Malior
  • 1,221
  • 8
  • 16
  • I think caching the compiled expression is an *absolute* must for this one – canton7 Mar 22 '19 at 14:45
  • 5
    Technically correct -- the best kind of correct -- but not something you want to propagate throughout a code base, as it makes null checks quite a bit more expensive. The plumbing needed to produce and process an entire expression tree for one parameter is considerable. – Jeroen Mostert Mar 22 '19 at 14:45
  • I agree. The price of getting rid of the second parameter is high. – Malior Mar 22 '19 at 16:11