/// <summary> /// Sets the value(s) of the specified property by name. If the /// <see cref="ObjectProperty"/> is null, then a new instance is /// created with the inital values provided. /// </summary> /// <remarks> /// This method should only be used when the ObjectProperty is null /// outside of the ScriptEngine, since it uses heavy relection. /// </remarks> /// <param name="propertyName">The <see cref="PropertyName"/> to assign</param> /// <param name="values">The values to set in the <see cref="ObjectProperty"/></param> public void SetValue(string propertyName, params object[] values) { // Fetch our property that we are setting the value to KeyValuePair <string, PropertyInfo> prop = GetProperty(propertyName); // If the first values argument is null, then we remove this property if (values == null) { Remove(prop.Value); return; } // If the value is null, then we create a new object property instance var obj = (ObjectProperty)prop.Value.GetValue(this); if (obj == null) { // === // Since the property is null, we must create a con script command. // So here, we will use the ReferenceType of this object, and property // name to create a fake token, and use that to set the value // === StringBuilder builder = new StringBuilder(); builder.Append($"{Token.TokenArgs.ReferenceType.Name}.{propertyName}"); foreach (object value in values) { builder.Append($" {value}"); } // Create a new Token Token token = Tokenizer.Tokenize(builder.ToString()); token.File = File; // Create the ObjectProperty instance, and set this Property to that instance obj = ObjectProperty.Create(prop.Value, this, token); // Add entry? IObjectPropertyCollection's add thier own properties Type type = obj.GetType(); if (type.GetInterface("IObjectPropertyCollection") == null) { Token.File?.AddProperty(obj); } } // Set the new object property values obj.SetValues(values); prop.Value.SetValue(this, obj); }
/// <summary> /// This method is responsible for parsing an object property /// reference line from inside of a .con or .ai file, and converting /// the property into a C# property /// </summary> /// <remarks> /// The type of value is figured out within the method, but only certain types of /// object types can be parsed here. /// </remarks> /// <param name="token">The token for this ObjectProperty</param> /// <param name="objectLevel">Specifies the nested object level for this Property</param> public virtual void Parse(Token token, int objectLevel = 0) { // Seperate our property name and values TokenArgs tokenArgs = token.TokenArgs; string propName = tokenArgs.PropertyNames[objectLevel]; // Fetch our property that we are setting the value to KeyValuePair <string, PropertyInfo> prop = GetProperty(propName); Type propType = prop.Value.PropertyType; bool isCollection = propType.GetInterface("IObjectPropertyCollection") != null; // Get the value that is set var value = prop.Value.GetValue(this); // Is this an object method, or Object Property? if (propType.BaseType.Name == "ObjectMethod") { // Object methods are always instantiated in the object's constructor ObjectMethod method = (ObjectMethod)value; ConFileEntry item = method.Invoke(token); // Add item to the file entry list if (item != null) { token.File?.AddEntry(item, token); } } else { // If the value is null, then we create a new object property instance ObjectProperty obj = (ObjectProperty)value; if (obj == null) { // Create instance and add it to the entries list obj = ObjectProperty.Create(prop.Value, this, token); // Add entry? Property Collections add thier own properties if (!isCollection) { token.File?.AddProperty(obj); } } // Create our instance, and parse obj.SetValue(token, objectLevel); prop.Value.SetValue(this, obj); } }
/// <summary> /// Creates a component (Sub Object) for an ObjectTemplate /// </summary> /// <param name="token"></param> /// <param name="comment"></param> protected virtual ConFileEntry Method_CreateComponent(Token token, string name) { Type type = this.GetType(); // Token correction token.Kind = TokenType.Component; // Ensure we have a map of components => property if (!ComponentTypes.ContainsKey(name)) { throw new Exception($"Unregistered component type \"{name}\""); } else if (!ComponentMap.ContainsKey(type.Name)) { throw new Exception($"Object type \"{type.Name}\" does not support Components"); } else if (!ComponentMap[type.Name].ContainsKey(name)) { throw new Exception($"Unsupported Component type \"{name}\" in \"{type.Name}\""); } // Get our field PropertyInfo property = ComponentMap[type.Name][name]; //Type componentType = property.PropertyType.GenericTypeArguments[0]; Type componentType = ComponentTypes[name]; var args = new object[] { name, token }; // Create instances var component = (ConFileObject)Activator.CreateInstance(componentType, args); //var objProperty = ObjectProperty.Create(property, component, token); var objProperty = ObjectProperty.Create(property, this, token); // Use reflection to set the value of the new component instance objProperty.SetValues(new object[] { component }, token); // Set value of this.{name} property.SetValue(this, objProperty); // Add component to file entries by returning it return(objProperty); }