-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPersistDynamic.cs
More file actions
310 lines (308 loc) · 11.2 KB
/
Copy pathPersistDynamic.cs
File metadata and controls
310 lines (308 loc) · 11.2 KB
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
using OsLib;
using JsonPit;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Dynamic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
/// <summary>
/// For now it looks like Jil can not completely replace a templated version of JsonFile/JsonItem with a dynamic version
/// So far we have to try to do a parallel implementation with JsonFileDynamic/JsonItemDynamic
/// use ItemsBase, maybe even extend it => JsonItemsDynamic
/// ALT
/// Try to derive JsonItemDynamic from JsonItem and see if that works since Jil is supposed to be able to deal with inheritance
/// ALTALT
/// reimplement everything (JsonFile, JsonItem, JsonItems) with object and/or dynamic => throw away type safety (??!?)
/// </summary>
namespace Persist
{
public static class DynamicExtensions
{
/// <summary>
/// creates an ExpandoObject; eliminates all methods and all non-public data
/// </summary>
/// <param name="value">object of any type</param>
/// <returns></returns>
public static dynamic ToDynamic(this object value)
{
IDictionary<string, object> expando = new ExpandoObject();
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType()))
expando.Add(property.Name, property.GetValue(value));
return expando as ExpandoObject;
}
/// <summary>
/// Extends a dynamic
/// </summary>
/// <param name="dyn"></param>
/// <param name="dynamicPartAsJson"></param>
/// <returns></returns>
//public static dynamic ExtendDynamicBy(dynamic dyn, string dynamicPartAsJson)
//{
// var dynString = JSON.SerializeDynamic(dyn);
// var extendedString = dynString.Substring(0, dynString.Length - 1) + "," + dynamicPartAsJson.Substring(1, dynamicPartAsJson.Length - 1);
// return JSON.DeserializeDynamic(extendedString);
//}
/// <summary>
/// Entends everything except a dynamic
/// </summar
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <param name="dynamicPartAsJson"></param>
/// <returns></returns>
public static dynamic ExtendBy<T>(this T value, string dynamicPartAsJson)
{
IDictionary<string, object> expando = new ExpandoObject();
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType()))
expando.Add(property.Name, property.GetValue(value));
var dict = JObject.Parse(dynamicPartAsJson);
//dynamic dynObj = JSON.DeserializeDynamic(dynamicPartAsJson) as ExpandoObject;
//var expandoDict = dynObj as IDictionary<string, object>;
foreach (var kv in dict)
expando.Add(kv.Key, kv.Value);
return expando as ExpandoObject;
}
}
/// <summary>
/// Adds dynamic object behavior to a JsonItem
/// </summary>
public class MyDynamicItem : Item
{
/// <summary>
/// directly accessible dynamic for setter getter access
/// </summary>
public dynamic d;
/// <summary>
/// creates a dynamic that contains the properties of the static and dynamic part of the DynamicItem
/// </summary>
/// <remarks>the static properties are starting with an uppercase letter</remarks>
/// <returns>a new dynamic object - just fields and properties, no methods</returns>
public override dynamic Clone()
{
//dynamic expando = new ExpandoObject();
#region get the d properties
IDictionary<string, object> expando = new ExpandoObject();
foreach (var dProperty in d)
expando.Add(dProperty.Key, dProperty.Value);
#endregion
#region add the known Properties of JsonItem that we also need
expando[nameof(Modified)] = Modified;
expando[nameof(Name)] = Name;
expando[nameof(Deleted)] = Deleted;
expando[nameof(Note)] = Note;
#endregion
return expando as ExpandoObject;
}
public MyDynamicItem(dynamic from, bool invalidate = false)
: base()
{
d = from;
try
{
Modified = (DateTimeOffset)from.Modified;
Name = (string)from.Name;
Deleted = (bool)from.Deleted;
Note = (string)from.Note;
}
catch (Exception ex)
{
throw new Exception($"{nameof(MyDynamicItem)} constructor didn't find a property in the passed-in dynamic", ex);
}
if (invalidate)
Invalidate();
}
public MyDynamicItem(string name, string comment, bool invalidate = true, string dynamicPartAsJson = "")
: base(name, comment, invalidate)
{
if (!string.IsNullOrEmpty(dynamicPartAsJson))
d = new MyDynamicItem(dynamicPartAsJson).d;
}
public MyDynamicItem(string dynamicPartAsJson)
{
dynamic obj = JObject.Parse(dynamicPartAsJson);
Name = obj.Name ?? Guid.NewGuid().ToString();
Note = obj.Note ?? "";
#region parse obj.Deleted into Deleted
{
var deleted = false;
var deletedString = (string)(obj.Deleted);
if (!string.IsNullOrEmpty(deletedString))
bool.TryParse(deletedString, out deleted);
Deleted = deleted;
}
#endregion
Modified = obj.Modified == null ? DateTimeOffset.UtcNow : DateTimeOffset.Parse((string)obj.Modified);
d = obj;
}
public MyDynamicItem()
{
}
}
// public class DynamicArrayHisto : JsonItem
// {
// /// <summary>
// /// directly accessible dynamic for setter getter access
// /// </summary>
// public Dictionary<string, History<JsonItem>> dict = new Dictionary<string, History<JsonItem>>();
// internal int Changes { get; set; }
// public dynamic this[string key]
// {
// get
// {
// return dict[key].Top()
// }
// set
// {
// #region quick insert if collection still empty
// if (dict.Count == 0)
// {
// dict[key] = value;
// Changes++;
// return true; // => invalidate
// }
// #endregion
// #region any incoming value could be outdated already => check all historic values for equality
// var q = (
// from x in Values
// where item.Time == x.Time && item.Value.CompareTo(x.Value) == 0 // same value AND same timestamp
// select x);
// #endregion
// #region add new value only if it's time/value combination is different from all stored historic values plus the latest value is different from the new one to insert
// if (q.Count() == 0 && item.Value.CompareTo(Values[0].Value) != 0) // different value, no matter which timestamp
// {
// Values.Insert(0, item);
// Values = Values.OrderByDescending(x => x.Time).Take(MaxHistory).ToList();
// // Invalidate(); let the caller handle it
// Changes++;
// return true;
// }
// #endregion
// return false;
// }
// }
// /// <summary>
// /// creates a dynamic that contains the properties of the static and dynamic part of the DynamicItem
// /// </summary>
// /// <remarks>the static properties are starting with an uppercase letter</remarks>
// /// <returns>a new dynamic object - just fields and properties, no methods</returns>
// public override dynamic Clone()
// {
// //dynamic expando = new ExpandoObject();
// #region get the d properties
// IDictionary<string, object> expando = new ExpandoObject();
// foreach (var dProperty in d)
// expando.Add(dProperty.Key, dProperty.Value);
// #endregion
// #region add the known Properties of JsonItem that we also need
// expando[nameof(Modified)] = Modified;
// expando[nameof(Name)] = Name;
// expando[nameof(Deleted)] = Deleted;
// expando[nameof(Note)] = Note;
// #endregion
// return expando as ExpandoObject;
// }
// public DynamicItem(dynamic from, bool invalidate = false)
// : base()
// {
// d = from;
// try
// {
// Modified = (DateTimeOffset)from.Modified;
// Name = (string)from.Name;
// Deleted = (bool)from.Deleted;
// Note = (string)from.Note;
// }
// catch (Exception ex)
// {
// throw new Exception($"{nameof(DynamicItem)} constructor didn't find a property in the passed-in dynamic", ex);
// }
// if (invalidate)
// Invalidate();
// }
// /// <summary>
// /// initializes the static and the dynamic part (via JSON)
// /// </summary>
// /// <param name="name">the identifying name of the object</param>
// /// <param name="comment">any kind of note</param>
// /// <param name="invalidate">perform invalidate during initialization</param>
// /// <param name="dynamicPartAsJson">optional: fills the dynamic part of the DynamicItem with the deserialized object defined by this JSON parameter</param>
// public DynamicItem(string name, string comment, bool invalidate = true, string dynamicPartAsJson = null)
// : base(name, comment, invalidate)
// {
// d = string.IsNullOrEmpty(dynamicPartAsJson) ? new ExpandoObject() : JSON.DeserializeDynamic(dynamicPartAsJson);
// }
// public DynamicItem(string dynamicPartAsJson)
// {
// dynamic obj = JSON.DeserializeDynamic(dynamicPartAsJson);
// Name = obj.Name ?? Guid.NewGuid().ToString();
// Note = obj.Note ?? "";
// #region parse obj.Deleted into Deleted
// {
// var deleted = false;
// var deletedString = (string)(obj.Deleted);
// if (!string.IsNullOrEmpty(deletedString))
// bool.TryParse(deletedString, out deleted);
// Deleted = deleted;
// }
// #endregion
// Modified = obj.Modified == null ? DateTimeOffset.UtcNow : DateTimeOffset.Parse((string)obj.Modified);
// d = obj;
// }
// public DynamicItem()
// {
// d = new ExpandoObject();
// }
// public DynamicItem(JObject obj)
// {
// foreach (JProperty x in (JToken)obj)
// { // if 'obj' is a JObject
// string name = x.Name;
// JToken value = x.Value;
// }
// //Name = (string)jToken[nameof(Name)];
// //Note = (string)jToken[nameof(Note)];
// //Modified = (DateTimeOffset)jToken[nameof(Modified)];
// //Deleted = (bool)jToken[nameof(Deleted)];
// }
// public DynamicItem(dynamic obj)
// {
// Name = obj.Name ?? Guid.NewGuid().ToString();
// Note = obj.Note ?? "";
// Deleted = obj.Deleted ?? false;
// Modified = obj.Modified == null ? DateTimeOffset.UtcNow : DateTimeOffset.Parse((string)obj.Modified);
// d = obj;
// }
//}
public static class MyDynamicItems
{
// TODO needs to be someplace else
//public static dynamic Clone(object)
/// <summary>Add property to a dynamic</summary>
/// <param name="expando"></param>
/// <param name="propertyName"></param>
/// <param name="propertyValue"></param>
/// <remarks>Excerpt From: Jay Hilyard, Stephen Teilhet. “C# 6.0 Cookbook.” iBooks. </remarks>
public static void AddProperty(ExpandoObject expando, string propertyName, object propertyValue)
{
// ExpandoObject supports IDictionary so we can extend it like this
var expandoDict = expando as IDictionary<string, object>;
if (expandoDict.ContainsKey(propertyName))
expandoDict[propertyName] = propertyValue;
else
expandoDict.Add(propertyName, propertyValue);
}
public static void AddEvent(ExpandoObject expando, string eventName, Action<object, EventArgs> handler)
{
var expandoDict = expando as IDictionary<string, object>;
if (expandoDict.ContainsKey(eventName))
expandoDict[eventName] = handler;
else
expandoDict.Add(eventName, handler);
}
}
}