Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
ObjectProperties.cs
1using System;
2using System.Collections.Generic;
3using System.Reflection;
8
10{
15 {
16 private IDictionary<string, object> dictionary;
17 private Type type;
18 private object obj;
19 private Dictionary<string, Tuple<PropertyInfo, FieldInfo, bool>> properties = null;
20 private readonly bool readOnly;
21
28 : this(Object, ContextVariables, true)
29 {
30 }
31
38 public ObjectProperties(object Object, Variables ContextVariables, bool ReadOnly)
39 : base()
40 {
41 if (Object is IElement E)
42 this.obj = E.AssociatedObjectValue;
43 else
44 this.obj = Object;
45
46 this.dictionary = this.obj as IDictionary<string, object>;
47 this.type = this.obj.GetType();
48 this.readOnly = ReadOnly;
49 this.ContextVariables = ContextVariables;
50 this.ConsoleOut = ContextVariables.ConsoleOut;
51 }
52
56 public object Object
57 {
58 get => this.obj;
59 set
60 {
61 if (value is IElement E)
62 this.obj = E.AssociatedObjectValue;
63 else
64 this.obj = value;
65
66 this.dictionary = this.obj as IDictionary<string, object>;
67
68 Type T = this.obj.GetType();
69
70 if (this.type != T)
71 {
72 this.type = T;
73 this.properties?.Clear();
74 }
75 }
76 }
77
83 public override bool ContainsVariable(string Name)
84 {
85 if (!(this.dictionary is null) && this.dictionary.ContainsKey(Name))
86 return true;
87
88 if (base.ContainsVariable(Name) || string.Compare(Name, "this", true) == 0)
89 return true;
90
91 lock (this.variables)
92 {
93 if (this.properties is null)
94 this.properties = new Dictionary<string, Tuple<PropertyInfo, FieldInfo, bool>>();
95
96 if (this.properties.TryGetValue(Name, out Tuple<PropertyInfo, FieldInfo, bool> Rec))
97 {
98 if (Rec.Item3)
99 {
100 try
101 {
102 ScriptNode.UnnestPossibleTaskSync(Rec.Item1.GetValue(this.obj, new object[] { Name })); // TODO: Async
103 return true;
104 }
105 catch (Exception)
106 {
107 return false;
108 }
109 }
110 else
111 return !(Rec is null);
112 }
113
114 PropertyInfo PI = this.type.GetRuntimeProperty(Name);
115 FieldInfo FI;
116
117 if (PI is null)
118 {
119 FI = this.type.GetRuntimeField(Name);
120
121 if (!(FI is null) && !FI.IsPublic)
122 {
123 this.properties[Name] = null;
124 return false;
125 }
126 }
127 else
128 {
129 FI = null;
130
131 if (!PI.CanRead || !PI.CanWrite || !PI.GetMethod.IsPublic || !PI.SetMethod.IsPublic)
132 {
133 this.properties[Name] = null;
134 return false;
135 }
136 }
137
138 if (PI is null && FI is null)
139 {
140 if (VectorIndex.TryGetIndexProperty(this.type, true, false, out PI, out _))
141 {
142 this.properties[Name] = new Tuple<PropertyInfo, FieldInfo, bool>(PI, FI, true);
143 return true;
144 }
145 else
146 {
147 this.properties[Name] = null;
148 return false;
149 }
150 }
151 else
152 {
153 this.properties[Name] = new Tuple<PropertyInfo, FieldInfo, bool>(PI, FI, false);
154 return true;
155 }
156 }
157 }
158
165 public override bool TryGetVariable(string Name, out Variable Variable)
166 {
167 Tuple<PropertyInfo, FieldInfo, bool> Rec;
168
169 if (string.Compare(Name, "this", true) == 0)
170 {
171 Variable = this.CreateVariable("this", this.obj);
172 return true;
173 }
174
175 if (!(this.dictionary is null) && this.dictionary.TryGetValue(Name, out object Value))
176 {
177 Variable = this.CreateVariable(Name, Value);
178 return true;
179 }
180
181 lock (this.variables)
182 {
183 if (this.properties is null)
184 this.properties = new Dictionary<string, Tuple<PropertyInfo, FieldInfo, bool>>();
185
186 if (!this.properties.TryGetValue(Name, out Rec))
187 {
188 PropertyInfo PI = this.type.GetRuntimeProperty(Name);
189 FieldInfo FI;
190
191 if (PI is null)
192 {
193 FI = this.type.GetRuntimeField(Name);
194
195 if (!(FI is null) && !FI.IsPublic)
196 FI = null;
197 }
198 else
199 {
200 FI = null;
201
202 if (!PI.CanRead || !PI.CanWrite || !PI.GetMethod.IsPublic || !PI.SetMethod.IsPublic)
203 PI = null;
204 }
205
206 if (PI is null && FI is null)
207 {
208 if (this.dictionary is null)
209 {
210 if (VectorIndex.TryGetIndexProperty(this.type, true, false, out PI, out _))
211 Rec = new Tuple<PropertyInfo, FieldInfo, bool>(PI, FI, true);
212 else
213 Rec = null;
214 }
215 else
216 Rec = null;
217 }
218 else
219 Rec = new Tuple<PropertyInfo, FieldInfo, bool>(PI, FI, false);
220
221 this.properties[Name] = Rec;
222 }
223 }
224
225 bool Result = false;
226
227 if (!(Rec is null))
228 {
229 Result = true; // null may be a valid response. Check variable collections first.
230
231 if (Rec.Item1 is null)
232 Value = ScriptNode.UnnestPossibleTaskSync(Rec.Item2.GetValue(this.obj)); // TODO: Async
233 else if (Rec.Item3)
234 {
235 try
236 {
237 Value = ScriptNode.UnnestPossibleTaskSync(Rec.Item1.GetValue(this.obj, new object[] { Name })); // TODO: Async
238 }
239 catch (KeyNotFoundException)
240 {
241 Value = null;
242 Result = false;
243 }
244 }
245 else
246 Value = ScriptNode.UnnestPossibleTaskSync(Rec.Item1.GetValue(this.obj)); // TODO: Async
247
248 if (!(Value is null))
249 {
250 Variable = this.CreateVariable(Name, Value);
251 return true;
252 }
253 }
254
255 if (base.TryGetVariable(Name, out Variable))
256 return true;
257
258 Variable = Result ? this.CreateVariable(Name, null) : null;
259 return Result;
260 }
261
268 public bool TryGetValue(string Name, out object Value)
269 {
270 Tuple<PropertyInfo, FieldInfo, bool> Rec;
271
272 if (string.Compare(Name, "this", true) == 0)
273 {
274 Value = this.obj;
275 return true;
276 }
277
278 if (!(this.dictionary is null) && this.dictionary.TryGetValue(Name, out Value))
279 return true;
280
281 lock (this.variables)
282 {
283 if (this.properties is null)
284 this.properties = new Dictionary<string, Tuple<PropertyInfo, FieldInfo, bool>>();
285
286 if (!this.properties.TryGetValue(Name, out Rec))
287 {
288 PropertyInfo PI = this.type.GetRuntimeProperty(Name);
289 FieldInfo FI;
290
291 if (PI is null)
292 {
293 FI = this.type.GetRuntimeField(Name);
294
295 if (!(FI is null) && !FI.IsPublic)
296 FI = null;
297 }
298 else
299 {
300 FI = null;
301
302 if (!PI.CanRead || !PI.CanWrite || !PI.GetMethod.IsPublic || !PI.SetMethod.IsPublic)
303 PI = null;
304 }
305
306 if (PI is null && FI is null)
307 {
308 if (this.dictionary is null)
309 {
310 if (VectorIndex.TryGetIndexProperty(this.type, true, false, out PI, out _))
311 Rec = new Tuple<PropertyInfo, FieldInfo, bool>(PI, FI, true);
312 else
313 Rec = null;
314 }
315 else
316 Rec = null;
317 }
318 else
319 Rec = new Tuple<PropertyInfo, FieldInfo, bool>(PI, FI, false);
320
321 this.properties[Name] = Rec;
322 }
323 }
324
325 bool Result = false;
326
327 if (!(Rec is null))
328 {
329 Result = true; // null may be a valid response. Check variable collections first.
330
331 if (Rec.Item1 is null)
332 Value = ScriptNode.UnnestPossibleTaskSync(Rec.Item2.GetValue(this.obj)); // TODO: Async
333 else if (Rec.Item3)
334 {
335 try
336 {
337 Value = ScriptNode.UnnestPossibleTaskSync(Rec.Item1.GetValue(this.obj, new object[] { Name })); // TODO: Async
338 }
339 catch (KeyNotFoundException)
340 {
341 Value = null;
342 Result = false;
343 }
344 }
345 else
346 Value = ScriptNode.UnnestPossibleTaskSync(Rec.Item1.GetValue(this.obj)); // TODO: Async
347
348 if (!(Value is null))
349 return true;
350 }
351
352 if (base.TryGetVariable(Name, out Variable Variable))
353 {
354 Value = Variable.ValueObject;
355 return true;
356 }
357
358 Value = null;
359 return Result;
360 }
361
362 private Variable CreateVariable(string Name, object Value)
363 {
364 if (Value is CaseInsensitiveString Cis)
365 return new Variable(Name, Cis.Value);
366 else
367 return new Variable(Name, Value);
368 }
369
377 public override Variable Add(string Name, object Value)
378 {
379 if (this.readOnly || string.Compare(Name, "this", true) == 0)
380 return base.Add(Name, Value);
381
382 Tuple<PropertyInfo, FieldInfo, bool> Rec;
383
384 if (!(this.dictionary is null))
385 {
386 this.dictionary[Name] = Value is IElement Element ? Element.AssociatedObjectValue : Value;
387 return null;
388 }
389
390 lock (this.variables)
391 {
392 if (this.properties is null)
393 this.properties = new Dictionary<string, Tuple<PropertyInfo, FieldInfo, bool>>();
394
395 if (!this.properties.TryGetValue(Name, out Rec))
396 {
397 PropertyInfo PI = this.type.GetRuntimeProperty(Name);
398 FieldInfo FI;
399
400 if (PI is null)
401 {
402 FI = this.type.GetRuntimeField(Name);
403
404 if (!(FI is null) && !FI.IsPublic)
405 FI = null;
406 }
407 else
408 {
409 FI = null;
410
411 if (!PI.CanRead || !PI.CanWrite || !PI.GetMethod.IsPublic || !PI.SetMethod.IsPublic)
412 PI = null;
413 }
414
415 if (PI is null && FI is null)
416 {
417 if (VectorIndex.TryGetIndexProperty(this.type, true, false, out PI, out _))
418 Rec = new Tuple<PropertyInfo, FieldInfo, bool>(PI, FI, true);
419 else
420 Rec = null;
421 }
422 else
423 Rec = new Tuple<PropertyInfo, FieldInfo, bool>(PI, FI, false);
424
425 this.properties[Name] = Rec;
426 }
427 }
428
429 if (!(Rec is null))
430 {
431 if (Value is IElement Element)
433
434 if (Rec.Item1 is null)
435 {
436 Type ValueType = Value?.GetType() ?? typeof(object);
437 Type FieldType = Rec.Item2.FieldType;
438
439 if (!FieldType.GetTypeInfo().IsAssignableFrom(ValueType.GetTypeInfo()))
440 Value = Expression.ConvertTo(Value, FieldType, null);
441
442 Rec.Item2.SetValue(this.obj, Value);
443 }
444 else
445 {
446 if (!Rec.Item1.CanWrite)
447 throw new InvalidOperationException("Property cannot be set.");
448 else if (!Rec.Item1.SetMethod.IsPublic)
449 throw new InvalidOperationException("Property not accessible.");
450 else
451 {
452 Type ValueType = Value?.GetType() ?? typeof(object);
453 Type PropertyType = Rec.Item1.PropertyType;
454
455 if (!PropertyType.GetTypeInfo().IsAssignableFrom(ValueType.GetTypeInfo()))
456 Value = Expression.ConvertTo(Value, PropertyType, null);
457
458 if (Rec.Item3)
459 Rec.Item1.SetValue(this.obj, Value, new object[] { Name });
460 else
461 Rec.Item1.SetValue(this.obj, Value);
462 }
463 }
464
465 return null;
466 }
467
468 if (this.ContextVariables.ContainsVariable(Name))
469 return this.ContextVariables.Add(Name, Value);
470 else
471 return base.Add(Name, Value);
472 }
473
474 }
475}
Represents a case-insensitive string.
Base class for all types of elements.
Definition: Element.cs:13
abstract object AssociatedObjectValue
Associated object value.
Definition: Element.cs:46
Class managing a script expression.
Definition: Expression.cs:39
static object ConvertTo(IElement Value, Type DesiredType, ScriptNode Node)
Tries to conevert an element value to a desired type.
Definition: Expression.cs:5127
Base class for all nodes in a parsed script tree.
Definition: ScriptNode.cs:69
static object UnnestPossibleTaskSync(object Result)
Checks if Result is an asynchronous results. If so, blocks the current thread until the result is co...
Definition: ScriptNode.cs:436
static bool TryGetIndexProperty(Type T, bool ForReading, bool ForWriting, out PropertyInfo PropertyInfo, out ParameterInfo[] Parameters)
Tries to get a one-dimensional index property of a Type.
Definition: VectorIndex.cs:133
override Variable Add(string Name, object Value)
Adds a variable to the collection.
bool TryGetValue(string Name, out object Value)
Tries to get the value, given its variable name.
ObjectProperties(object Object, Variables ContextVariables)
Object properties.
ObjectProperties(object Object, Variables ContextVariables, bool ReadOnly)
Object properties.
override bool TryGetVariable(string Name, out Variable Variable)
Tries to get a variable object, given its name.
override bool ContainsVariable(string Name)
If the collection contains a variable with a given name.
Contains information about a variable.
Definition: Variable.cs:10
object ValueObject
Object Value of variable.
Definition: Variable.cs:88
Collection of variables.
Definition: Variables.cs:25
IContextVariables ContextVariables
Variables available during the current context.
Definition: Variables.cs:228
Dictionary< string, Variable > variables
Internal set of variables.
Definition: Variables.cs:29
Basic interface for all types of elements.
Definition: IElement.cs:20
bool ContainsVariable(string Name)
If the collection contains a variable with a given name.
Variable Add(string Name, object Value)
Adds a variable to the collection.