4

In a netstandard 2.0 application, I have the following method that is part of a static class:

public static class Argument 
{    
    /// <param name="inst">Inst.</param>
    /// <param name="instName">Inst name.</param>
    /// <exception cref="ArgumentException">
    /// Thrown if :
    /// <paramref name="inst" /> is not specified in a local time zone.
    /// </exception>
    public static void ThrowIfIsNotLocal(in DateTime inst, string instName)
    {
        if (inst.Kind != DateTimeKind.Local)
            throw new ArgumentException(instName, $"{instName} is not expressed in a local time-zone.");
    }
}

In my program that is running .netcore 2.0, I have the following line that generates an error:

Argument.ThrowIfIsNotLocal(DateTime.Now, "timestamp");

argument is value while parameter is declared as in

Why is DateTime.Now causing the error to appear?

Kzryzstof
  • 7,688
  • 10
  • 61
  • 108

1 Answers1

5

The method signature states that the parameter needs to be passed by reference, not by value. That means that you need to have some sort of storage location that can be referenced to pass into that method.

The result of a property getter is not a variable; it's not something that you can have a reference to. It's just a value, hence the error message.

You need to both have a variable, rather than just a value, and also use the in keyword when calling the method to indicate that you're intending to pass a reference to the variable, rather than just the value of the variable.

var now = DateTime.Now;
ThrowIfIsNotLocal(in now, "");

Of course, there's no real reason to pass this variable by reference in the first place. I'd suggest not doing so, and simply passing the parameter by value. That way callers won't need to go through all of this when they just have a value, not a variable.

Servy
  • 202,030
  • 26
  • 332
  • 449
  • The reason of passing a struct by ref in this case is to avoid the copy and to indicate that the method does not modify the value. – Kzryzstof Aug 13 '18 at 21:43
  • Oh... Trying your solution changed the error! It now complains that readonly reference is a C# 7.2 feature. I guess I have to enable C# 7.2 in my .netcore app. – Kzryzstof Aug 13 '18 at 21:44
  • You can add the difference between `in` and `ref` keywords as [in the spec](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/in-parameter-modifier) (can't change the value of the passed variable inside the method) – Ivan García Topete Aug 13 '18 at 21:46
  • @Kzrystof: then how is that different from my solution. Btw, the original, with DateTime.Now seems to build as well for me. But I must say, my VS is reacting a bit strange these days. – Stefan Aug 13 '18 at 21:48
  • @Stefan The different lies in the caller specifying the in parameter as well. – Kzryzstof Aug 13 '18 at 21:50
  • @Kzrystof Constructing the reference and passing the reference is going to be as much work as passing the value, as the size of the value is going to be no bigger than the size of the reference. If you pass it by value it also can't be changed. – Servy Aug 13 '18 at 21:54
  • @Servy Looks like it is not the case :) As it can be seen [in this article](https://dotnetcoretutorials.com/2018/01/08/new-keyword-c-7-2/), the performance improvement can be significant for methods that are called often. – Kzryzstof Aug 13 '18 at 22:00
  • 3
    @Kzrystof 1) That involves a type that is much larger than a reference 2) the benchmark involves returning a value that is never used, thus the whole thing could theoretically be elided entirely. It's not a meaningful benchmark. Again, your code involves a type that is no larger than a reference, and given that the caller apparently doesn't always already have a variable, it means that they're doing a copy *anyway*, to put it in a variable (that wouldn't otherwise be needed) just for the purposes of this method. I didn't say it's *never* appropriate to use `in`, just that it isn't *here*. – Servy Aug 13 '18 at 22:03
  • @Servy understood :) – Kzryzstof Aug 13 '18 at 22:05
  • 2
    @Kzrystof It's also worth nothing that the second half of that article is them talking about how hard of a time they had creating any examples that resulted in a performance difference. That should give you some idea that this isn't something you just slap on every parameter that you have, but rather something for *very specific* situations. – Servy Aug 13 '18 at 22:06