Example #1
0
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes")] // TODO: fix
        public TValue GetOrCreateValue(TKey key, Func <TValue> create)
        {
            bool lockTaken = false;

            try {
                MonitorUtils.Enter(data, ref lockTaken);

                PublishInfo <TValue> pubValue;
                if (data.TryGetValue(key, out pubValue))
                {
                    if (pubValue.Value == null && pubValue.Exception == null)
                    {
                        pubValue.PrepareForWait();
                        MonitorUtils.Exit(data, ref lockTaken);

                        try {
                            pubValue.WaitForPublish();
                        } finally {
                            MonitorUtils.Enter(data, ref lockTaken);
                            pubValue.FinishWait();
                        }
                    }

                    if (pubValue.Exception != null)
                    {
                        throw new Exception("Error", pubValue.Exception);
                    }

                    return(pubValue.Value);
                }

                TValue ret;
                // publish the empty PublishInfo
                data[key] = pubValue = new PublishInfo <TValue>();

                // release our lock while we create the new value
                // then re-acquire the lock and publish the info.
                MonitorUtils.Exit(data, ref lockTaken);

                try {
                    try {
                        ret = create();
                        Debug.Assert(ret != null, "Can't publish a null value");
                    } finally {
                        MonitorUtils.Enter(data, ref lockTaken);
                    }
                } catch (Exception e) {
                    pubValue.PublishError(e);
                    throw;
                }

                pubValue.PublishValue(ret);
                return(ret);
            } finally {
                if (lockTaken)
                {
                    Monitor.Exit(data);
                }
            }
        }