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;
3using System.Reflection;
8
10{
15 {
16 private IDictionary<string, object> dictionary;
17 private Type type;
18 private object obj;
19 private Dictionary<string, PropertyRecord> properties = null;
20 private readonly bool readOnly;
21
22 private class PropertyRecord
23 {
24 public PropertyInfo Property;
25 public ParameterInfo[] IndexArguments;
26 public FieldInfo Field;
27 public int NrIndexParameters;
28 public bool IsStringIndex;
29
30 public PropertyRecord(PropertyInfo Property, FieldInfo Field)
31 {
32 this.Property = Property;
33 this.Field = Field;
34 this.IndexArguments = null;
35 this.NrIndexParameters = 0;
36 this.IsStringIndex = false;
37 }
38
39 public PropertyRecord(PropertyInfo Property, FieldInfo Field, ParameterInfo[] IndexArguments)
40 {
41 this.Property = Property;
42 this.Field = Field;
43 this.IndexArguments = IndexArguments;
44
45 if (IndexArguments is null)
46 {
47 this.NrIndexParameters = 0;
48 this.IsStringIndex = false;
49 }
50 else
51 {
52 this.NrIndexParameters = this.IndexArguments.Length;
53 this.IsStringIndex = this.NrIndexParameters == 1 &&
54 this.IndexArguments[0].ParameterType == typeof(string);
55 }
56 }
57
58 public object[] GetIndexArguments(string Name)
59 {
60 if (this.IsStringIndex)
61 return new object[] { Name };
62
63 object Converted = Expression.ConvertTo(Name, this.IndexArguments[0].ParameterType, null);
64
65 return new object[] { Converted };
66 }
67 }
68
75 : this(Object, ContextVariables, true)
76 {
77 }
78
85 public ObjectProperties(object Object, Variables ContextVariables, bool ReadOnly)
86 : base()
87 {
88 if (Object is IElement E)
89 this.obj = E.AssociatedObjectValue;
90 else
91 this.obj = Object;
92
93 this.dictionary = this.obj as IDictionary<string, object>;
94 this.type = this.obj.GetType();
95 this.readOnly = ReadOnly;
96 this.ContextVariables = ContextVariables;
97 this.ConsoleOut = ContextVariables.ConsoleOut;
98 }
99
103 public object Object
104 {
105 get => this.obj;
106 set
107 {
108 if (value is IElement E)
109 this.obj = E.AssociatedObjectValue;
110 else
111 this.obj = value;
112
113 this.dictionary = this.obj as IDictionary<string, object>;
114
115 Type T = this.obj.GetType();
116
117 if (this.type != T)
118 {
119 this.type = T;
120 this.properties?.Clear();
121 }
122 }
123 }
124
130 public override bool ContainsVariable(string Name)
131 {
132 if (!(this.dictionary is null) && this.dictionary.ContainsKey(Name))
133 return true;
134
135 if (base.ContainsVariable(Name) || string.Compare(Name, "this", true) == 0)
136 return true;
137
138 lock (this.variables)
139 {
140 if (this.properties is null)
141 this.properties = new Dictionary<string, PropertyRecord>();
142
143 if (this.properties.TryGetValue(Name, out PropertyRecord Rec))
144 {
145 if (Rec.NrIndexParameters == 1)
146 {
147 try
148 {
149 ScriptNode.UnnestPossibleTaskSync(Rec.Property.GetValue(this.obj, Rec.GetIndexArguments(Name))); // TODO: Async
150 return true;
151 }
152 catch (Exception)
153 {
154 return false;
155 }
156 }
157 else
158 return !(Rec is null);
159 }
160
161 PropertyInfo PI = this.type.GetRuntimeProperty(Name);
162 FieldInfo FI;
163
164 if (PI is null)
165 {
166 FI = this.type.GetRuntimeField(Name);
167
168 if (!(FI is null) && !FI.IsPublic)
169 {
170 this.properties[Name] = null;
171 return false;
172 }
173 }
174 else
175 {
176 FI = null;
177
178 if (!PI.CanRead || !PI.CanWrite || !PI.GetMethod.IsPublic || !PI.SetMethod.IsPublic)
179 {
180 this.properties[Name] = null;
181 return false;
182 }
183 }
184
185 if (PI is null && FI is null)
186 {
187 if (VectorIndex.TryGetIndexProperty(this.type, true, false, out PI,
188 out ParameterInfo[] IndexArguments))
189 {
190 this.properties[Name] = new PropertyRecord(PI, FI, IndexArguments);
191 return true;
192 }
193 else
194 {
195 this.properties[Name] = null;
196 return false;
197 }
198 }
199 else
200 {
201 this.properties[Name] = new PropertyRecord(PI, FI);
202 return true;
203 }
204 }
205 }
206
213 public override bool TryGetVariable(string Name, out Variable Variable)
214 {
215 PropertyRecord Rec;
216
217 if (string.Compare(Name, "this", true) == 0)
218 {
219 Variable = this.CreateVariable("this", this.obj);
220 return true;
221 }
222
223 if (!(this.dictionary is null) && this.dictionary.TryGetValue(Name, out object Value))
224 {
225 Variable = this.CreateVariable(Name, Value);
226 return true;
227 }
228
229 lock (this.variables)
230 {
231 if (this.properties is null)
232 this.properties = new Dictionary<string, PropertyRecord>();
233
234 if (!this.properties.TryGetValue(Name, out Rec))
235 {
236 PropertyInfo PI = this.type.GetRuntimeProperty(Name);
237 FieldInfo FI;
238
239 if (PI is null)
240 {
241 FI = this.type.GetRuntimeField(Name);
242
243 if (!(FI is null) && !FI.IsPublic)
244 FI = null;
245 }
246 else
247 {
248 FI = null;
249
250 if (!PI.CanRead || !PI.CanWrite || !PI.GetMethod.IsPublic || !PI.SetMethod.IsPublic)
251 PI = null;
252 }
253
254 if (PI is null && FI is null)
255 {
256 if (this.dictionary is null)
257 {
258 if (VectorIndex.TryGetIndexProperty(this.type, true, false, out PI,
259 out ParameterInfo[] IndexArguments))
260 {
261 Rec = new PropertyRecord(PI, FI, IndexArguments);
262 }
263 else
264 Rec = null;
265 }
266 else
267 Rec = null;
268 }
269 else
270 Rec = new PropertyRecord(PI, FI);
271
272 this.properties[Name] = Rec;
273 }
274 }
275
276 bool Result = false;
277
278 if (!(Rec is null))
279 {
280 Result = true; // null may be a valid response. Check variable collections first.
281
282 if (Rec.Property is null)
283 Value = ScriptNode.UnnestPossibleTaskSync(Rec.Field.GetValue(this.obj)); // TODO: Async
284 else if (Rec.NrIndexParameters == 1)
285 {
286 try
287 {
288 Value = ScriptNode.UnnestPossibleTaskSync(Rec.Property.GetValue(this.obj, Rec.GetIndexArguments(Name))); // TODO: Async
289 }
290 catch (KeyNotFoundException)
291 {
292 Value = null;
293 Result = false;
294 }
295 }
296 else
297 Value = ScriptNode.UnnestPossibleTaskSync(Rec.Property.GetValue(this.obj)); // TODO: Async
298
299 if (Value is null)
300 {
302 {
303 Variable = new Variable(Name, ConstantElement);
304 return true;
305 }
306 }
307 else
308 {
309 Variable = this.CreateVariable(Name, Value);
310 return true;
311 }
312 }
313
314 if (base.TryGetVariable(Name, out Variable))
315 return true;
316
317 Variable = Result ? this.CreateVariable(Name, null) : null;
318 return Result;
319 }
320
327 public bool TryGetValue(string Name, out object Value)
328 {
329 PropertyRecord Rec;
330
331 if (string.Compare(Name, "this", true) == 0)
332 {
333 Value = this.obj;
334 return true;
335 }
336
337 if (!(this.dictionary is null) && this.dictionary.TryGetValue(Name, out Value))
338 return true;
339
340 lock (this.variables)
341 {
342 if (this.properties is null)
343 this.properties = new Dictionary<string, PropertyRecord>();
344
345 if (!this.properties.TryGetValue(Name, out Rec))
346 {
347 PropertyInfo PI = this.type.GetRuntimeProperty(Name);
348 FieldInfo FI;
349
350 if (PI is null)
351 {
352 FI = this.type.GetRuntimeField(Name);
353
354 if (!(FI is null) && !FI.IsPublic)
355 FI = null;
356 }
357 else
358 {
359 FI = null;
360
361 if (!PI.CanRead || !PI.CanWrite || !PI.GetMethod.IsPublic || !PI.SetMethod.IsPublic)
362 PI = null;
363 }
364
365 if (PI is null && FI is null)
366 {
367 if (this.dictionary is null)
368 {
369 if (VectorIndex.TryGetIndexProperty(this.type, true, false, out PI,
370 out ParameterInfo[] IndexArguments))
371 {
372 Rec = new PropertyRecord(PI, FI, IndexArguments);
373 }
374 else
375 Rec = null;
376 }
377 else
378 Rec = null;
379 }
380 else
381 Rec = new PropertyRecord(PI, FI);
382
383 this.properties[Name] = Rec;
384 }
385 }
386
387 bool Result = false;
388
389 if (!(Rec is null))
390 {
391 Result = true; // null may be a valid response. Check variable collections first.
392
393 if (Rec.Property is null)
394 Value = ScriptNode.UnnestPossibleTaskSync(Rec.Field.GetValue(this.obj)); // TODO: Async
395 else if (Rec.NrIndexParameters == 1)
396 {
397 try
398 {
399 Value = ScriptNode.UnnestPossibleTaskSync(Rec.Property.GetValue(this.obj, Rec.GetIndexArguments(Name))); // TODO: Async
400 }
401 catch (KeyNotFoundException)
402 {
403 Value = null;
404 Result = false;
405 }
406 }
407 else
408 Value = ScriptNode.UnnestPossibleTaskSync(Rec.Property.GetValue(this.obj)); // TODO: Async
409
410 if (!(Value is null))
411 return true;
412 }
413
414 if (base.TryGetVariable(Name, out Variable Variable))
415 {
416 Value = Variable.ValueObject;
417 return true;
418 }
419
420 Value = null;
421 return Result;
422 }
423
424 private Variable CreateVariable(string Name, object Value)
425 {
426 if (Value is CaseInsensitiveString Cis)
427 return new Variable(Name, Cis.Value);
428 else
429 return new Variable(Name, Value);
430 }
431
439 public override Variable Add(string Name, object Value)
440 {
441 if (this.readOnly || string.Compare(Name, "this", true) == 0)
442 return base.Add(Name, Value);
443
444 PropertyRecord Rec;
445
446 if (!(this.dictionary is null))
447 {
448 this.dictionary[Name] = Value is IElement Element ? Element.AssociatedObjectValue : Value;
449 return null;
450 }
451
452 lock (this.variables)
453 {
454 if (this.properties is null)
455 this.properties = new Dictionary<string, PropertyRecord>();
456
457 if (!this.properties.TryGetValue(Name, out Rec))
458 {
459 PropertyInfo PI = this.type.GetRuntimeProperty(Name);
460 FieldInfo FI;
461
462 if (PI is null)
463 {
464 FI = this.type.GetRuntimeField(Name);
465
466 if (!(FI is null) && !FI.IsPublic)
467 FI = null;
468 }
469 else
470 {
471 FI = null;
472
473 if (!PI.CanRead || !PI.CanWrite || !PI.GetMethod.IsPublic || !PI.SetMethod.IsPublic)
474 PI = null;
475 }
476
477 if (PI is null && FI is null)
478 {
479 if (VectorIndex.TryGetIndexProperty(this.type, true, false, out PI,
480 out ParameterInfo[] IndexArguments))
481 {
482 Rec = new PropertyRecord(PI, FI, IndexArguments);
483 }
484 else
485 Rec = null;
486 }
487 else
488 Rec = new PropertyRecord(PI, FI);
489
490 this.properties[Name] = Rec;
491 }
492 }
493
494 if (!(Rec is null))
495 {
496 if (Value is IElement Element)
498
499 if (Rec.Property is null)
500 {
501 Type ValueType = Value?.GetType() ?? typeof(object);
502 Type FieldType = Rec.Field.FieldType;
503
504 if (!FieldType.IsAssignableFrom(ValueType.GetTypeInfo()))
505 Value = Expression.ConvertTo(Value, FieldType, null);
506
507 Rec.Field.SetValue(this.obj, Value);
508 }
509 else
510 {
511 if (!Rec.Property.CanWrite)
512 throw new InvalidOperationException("Property cannot be set.");
513 else if (!Rec.Property.SetMethod.IsPublic)
514 throw new InvalidOperationException("Property not accessible.");
515 else
516 {
517 Type ValueType = Value?.GetType() ?? typeof(object);
518 Type PropertyType = Rec.Property.PropertyType;
519
520 if (!PropertyType.IsAssignableFrom(ValueType.GetTypeInfo()))
521 Value = Expression.ConvertTo(Value, PropertyType, null);
522
523 if (Rec.NrIndexParameters == 1)
524 Rec.Property.SetValue(this.obj, Value, Rec.GetIndexArguments(Name));
525 else
526 Rec.Property.SetValue(this.obj, Value);
527 }
528 }
529
530 return null;
531 }
532
533 if (this.ContextVariables.ContainsVariable(Name))
534 return this.ContextVariables.Add(Name, Value);
535 else
536 return base.Add(Name, Value);
537 }
538
539 }
540}
Represents a case-insensitive string.
Base class for all types of elements.
Definition: Element.cs:14
abstract object AssociatedObjectValue
Associated object value.
Definition: Element.cs:43
Class managing a script expression.
Definition: Expression.cs:41
static bool TryGetConstant(string Name, Variables Variables, out IElement ValueElement)
Tries to get a constant value, given its name.
Definition: Expression.cs:3382
static object ConvertTo(IElement Value, Type DesiredType, ScriptNode Node)
Tries to conevert an element value to a desired type.
Definition: Expression.cs:5385
Represents a constant element value.
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:460
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:138
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:232
Dictionary< string, Variable > variables
Internal set of variables.
Definition: Variables.cs:29
Basic interface for all types of elements.
Definition: IElement.cs:21
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.