You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
224 lines
5.7 KiB
224 lines
5.7 KiB
#if FAT |
|
|
|
using System; |
|
using System.Threading; |
|
using LinqInternal.Core; |
|
|
|
namespace LinqInternal.Threading.Needles |
|
{ |
|
[Serializable] |
|
[System.Diagnostics.DebuggerNonUserCode] |
|
internal class LazyNeedle<T> : PromiseNeedle<T>, IEquatable<LazyNeedle<T>> |
|
{ |
|
[NonSerialized] |
|
private Thread _runnerThread; |
|
|
|
private Func<T> _valueFactory; |
|
|
|
public LazyNeedle() |
|
: base(true) |
|
{ |
|
_valueFactory = null; |
|
} |
|
|
|
public LazyNeedle(T target) |
|
: base(target) |
|
{ |
|
_valueFactory = null; |
|
} |
|
|
|
public LazyNeedle(Func<T> valueFactory) |
|
: base(false) |
|
{ |
|
if (valueFactory == null) |
|
{ |
|
throw new ArgumentNullException("valueFactory"); |
|
} |
|
_valueFactory = valueFactory; |
|
} |
|
|
|
public LazyNeedle(Func<T> valueFactory, bool cacheExceptions) |
|
: base(false) |
|
{ |
|
if (valueFactory == null) |
|
{ |
|
throw new ArgumentNullException("valueFactory"); |
|
} |
|
_valueFactory = valueFactory; |
|
if (cacheExceptions) |
|
{ |
|
_valueFactory = () => |
|
{ |
|
try |
|
{ |
|
return valueFactory.Invoke(); |
|
} |
|
catch (Exception exc) |
|
{ |
|
_valueFactory = FuncHelper.GetThrowFunc<T>(exc); |
|
throw; |
|
} |
|
}; |
|
} |
|
} |
|
|
|
public override T Value |
|
{ |
|
get |
|
{ |
|
Initialize(); |
|
return base.Value; |
|
} |
|
set |
|
{ |
|
base.Value = value; |
|
ReleaseValueFactory(); |
|
} |
|
} |
|
|
|
protected Thread RunnerThread |
|
{ |
|
get { return _runnerThread; } |
|
} |
|
|
|
public override bool Equals(object obj) |
|
{ |
|
return obj is LazyNeedle<T> && base.Equals(obj); |
|
} |
|
|
|
public bool Equals(LazyNeedle<T> other) |
|
{ |
|
return other != null && base.Equals(other); |
|
} |
|
|
|
public override int GetHashCode() |
|
{ |
|
return base.GetHashCode(); |
|
} |
|
|
|
public virtual void Initialize() |
|
{ |
|
if (_runnerThread == Thread.CurrentThread) |
|
{ |
|
throw new InvalidOperationException(); |
|
} |
|
var valueFactory = Interlocked.Exchange(ref _valueFactory, null); |
|
if (valueFactory == null) |
|
{ |
|
base.Wait(); |
|
} |
|
else |
|
{ |
|
InitializeExtracted(valueFactory); |
|
} |
|
} |
|
|
|
public void ReleaseValueFactory() |
|
{ |
|
Volatile.Write(ref _valueFactory, null); |
|
} |
|
|
|
public override void Wait() |
|
{ |
|
if (_runnerThread == Thread.CurrentThread) |
|
{ |
|
throw new InvalidOperationException(); |
|
} |
|
base.Wait(); |
|
} |
|
|
|
public override void Wait(CancellationToken cancellationToken) |
|
{ |
|
if (_runnerThread == Thread.CurrentThread) |
|
{ |
|
throw new InvalidOperationException(); |
|
} |
|
base.Wait(cancellationToken); |
|
} |
|
|
|
public override void Wait(int milliseconds) |
|
{ |
|
if (_runnerThread == Thread.CurrentThread) |
|
{ |
|
throw new InvalidOperationException(); |
|
} |
|
base.Wait(milliseconds); |
|
} |
|
|
|
public override void Wait(TimeSpan timeout) |
|
{ |
|
if (_runnerThread == Thread.CurrentThread) |
|
{ |
|
throw new InvalidOperationException(); |
|
} |
|
base.Wait(timeout); |
|
} |
|
|
|
public override void Wait(int milliseconds, CancellationToken cancellationToken) |
|
{ |
|
if (_runnerThread == Thread.CurrentThread) |
|
{ |
|
throw new InvalidOperationException(); |
|
} |
|
base.Wait(milliseconds, cancellationToken); |
|
} |
|
|
|
public override void Wait(TimeSpan timeout, CancellationToken cancellationToken) |
|
{ |
|
if (_runnerThread == Thread.CurrentThread) |
|
{ |
|
throw new InvalidOperationException(); |
|
} |
|
base.Wait(timeout, cancellationToken); |
|
} |
|
|
|
protected virtual void Initialize(Action beforeInitialize) |
|
{ |
|
if (beforeInitialize == null) |
|
{ |
|
throw new ArgumentNullException("beforeInitialize"); |
|
} |
|
if (_runnerThread == Thread.CurrentThread) |
|
{ |
|
throw new InvalidOperationException(); |
|
} |
|
var valueFactory = Interlocked.Exchange(ref _valueFactory, null); |
|
if (valueFactory == null) |
|
{ |
|
base.Wait(); |
|
} |
|
else |
|
{ |
|
try |
|
{ |
|
beforeInitialize.Invoke(); |
|
} |
|
finally |
|
{ |
|
InitializeExtracted(valueFactory); |
|
} |
|
} |
|
} |
|
|
|
private void InitializeExtracted(Func<T> valueFactory) |
|
{ |
|
_runnerThread = Thread.CurrentThread; |
|
try |
|
{ |
|
base.Value = valueFactory.Invoke(); |
|
} |
|
catch (Exception exception) |
|
{ |
|
Interlocked.CompareExchange(ref _valueFactory, valueFactory, null); |
|
SetError(exception); |
|
throw; |
|
} |
|
finally |
|
{ |
|
_runnerThread = null; |
|
} |
|
} |
|
} |
|
} |
|
|
|
#endif |