-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathPartial.cs
135 lines (112 loc) · 2.95 KB
/
Partial.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* Date: 18.11.2017, Time: 1:46 */
using System;
using System.Collections.Generic;
namespace IllidanS4.SharpUtils.ObjectModel
{
/// <summary>
/// Represents a container whose contents may not be loaded yet.
/// </summary>
public class Partial<T> : Lazy<T>, ICompletable
{
protected ICompletable Container{get; private set;}
Notifier notifier;
public Partial(ICompletable completable, out Partial<T> property) : this(new Notifier(completable), out property)
{
Container = completable;
}
private Partial(Notifier notifier, out Partial<T> property) : base(notifier.WaitForValue)
{
property = this;
notifier.Parent = this;
}
public Partial(ICompletable completable) : this(new Notifier(completable))
{
Container = completable;
}
private Partial(Notifier notifier) : base(notifier.WaitForValue)
{
this.notifier = notifier;
}
public void MarkCreated()
{
if(notifier == null) throw new InvalidOperationException("The property was already created.");
notifier.Parent = this;
notifier = null;
}
class Notifier
{
readonly ICompletable completable;
bool valueReceived;
T value;
Partial<T> parent;
public Partial<T> Parent{
get{
return parent;
}
set{
parent = value;
completable.RegisterReceiver(parent, OnValueReceived);
}
}
public Notifier(ICompletable completable)
{
this.completable = completable;
}
public T WaitForValue()
{
if(valueReceived) return value;
if(parent == null) throw new InvalidOperationException("The object hasn't been initialized yet.");
OnValueObtained(completable.WaitForProperty(parent));
return value;
}
private void OnValueObtained(T value)
{
if(valueReceived) return;
this.value = value;
valueReceived = true;
foreach(var receiver in parent.receivers)
{
receiver(value);
}
}
private void OnValueReceived(T value)
{
OnValueObtained(value);
//value = parent.Value; //causes recursion
}
}
bool ICompletable.IsCompleted{
get{
return this.IsValueCreated;
}
}
public void CreateValue()
{
var value = this.Value;
}
void ICompletable.Complete()
{
CreateValue();
}
readonly List<Action<T>> receivers = new List<Action<T>>();
public virtual void RegisterReceiver<TArg>(Partial<TArg> property, Action<TArg> valueReceiver)
{
if(!Object.ReferenceEquals(property, this)) throw Completable.InvalidProperty();
if(IsValueCreated)
{
To<Action<T>>.Cast(valueReceiver).Invoke(Value);
}else{
receivers.Add(To<Action<T>>.Cast(valueReceiver));
}
}
public virtual TArg WaitForProperty<TArg>(Partial<TArg> property)
{
if(!Object.ReferenceEquals(property, this)) throw Completable.InvalidProperty();
return To<TArg>.Cast(Value);
}
public virtual bool ContainsProperty<TArg>(Partial<TArg> property)
{
return Object.ReferenceEquals(property, this);
}
}
}