InvalidOperationException in my Lazy<> value fa

2019-04-03 01:55发布

问题:

I have a class containing something like the following:

public static class Config
{
    private static Lazy<ConfigSource> _cfgSrc = new Lazy<ConfigSource>(
        () => { /* "ValueFactory" here... */ },
        true);

    public static ConfigSource ConfigSource
    {
        get { return _cfgSrc.Value; }
    }
}

In accessing the ConfigSource property, I encountered this InvalidOperationException:

ValueFactory attempted to access the Value property of this instance.

I don't see anything in my "value factory" method that accesses the Value property. Is there anything else that could be triggering this exception? This problem only happens intermittently, but once it does, it takes resetting IIS to clear up the Exception (which appears to be cached once it occurs).

回答1:

It turned out that this error only occurred when trying to inspect the Value property of the Lazy<> in the Visual Studio debugger. Doing so appeared to create a deadlock because the accessing of Value then seemed to hang the thread for a long time until the InvalidOperationException finally occurred. I could never intercept the original Exception, so I couldn't see the inner stacktrace.

I'm just chalking this up as a bug in Visual Studio or their implementation of Lazy<>.



回答2:

ValueFactory attempted to access the Value property of this instance.

It may help somebody, I was able to fix that error by inspecting my entire ValueFactory procedure. In my example, I was creating a simple model and the linked it with some other data but during the linking process I was accessing the Value property in a singleton and that caused the error.

So accessing the Value of a Lazy object inside the ValueFactory throws such an error. As the error message is already indicating ;-)



回答3:

This has also happened to me with circular dependencies, so if these steps lead you nowhere, try double checking the stacktrace and verifying that there are no circular dependencies.



回答4:

The behavior of Lazy<T> is to cache exceptions thrown by the ValueFactory. This can lead to potentially confusing behavior due to the paucity of information given in the InvalidOperationException message. Microsoft was made aware of this issue through Connect, however, it is marked as Wont Fix as they feel there is enough information in the exception itself to diagnose the problem.

If there is an inner exception for the IOE you receive, it should (not saying it will) contain enough information to continue onwards. Another possibility is you have a try...catch blocks which rethrows exceptions (throw ex; instead of throw;), you will lose valuable information.



回答5:

To make sure your exception isn't cached, use LazyThreadSafetyMode.PublicationOnly as a second parameter, instead of true.

Using true, you'll end up with a LazyThreadSafetyMode.ExecutionAndPublication. This will ensure only one thread enteres the ValueFactory method, but also ensures exceptions will be cached.

  private static Lazy<ConfigSource> _cfgSrc = new Lazy<ConfigSource>(
        () => { /* "ValueFactory" here... */ },
        LazyThreadSafetyMode.PublicationOnly);

See the link sixlettervariables provided for more information.