public static string MakeArray( [ExcelArgument(Description = "Name of the array object to create.")] string name, [ExcelArgument(Description = "Array of values.")] object[] values) { if (values == null || values.Length == 0) { throw new NNXException("Array cannot be empty."); } object result; const string inconsistentArrayMessage = "Array must contain either only numbers or only strings. " + "Encountered both in this array."; const string badTypeMessage = "Array elements must be either numbers or strings. Element" + " at position {0} was neither number nor string."; // Determine the type of the array. To do that, // find the first element that is neither null nor empty. var firstNonEmptyIndex = 0; while (firstNonEmptyIndex < values.Length && IsEmpty(values[firstNonEmptyIndex])) { firstNonEmptyIndex++; } if (firstNonEmptyIndex >= values.Length) { throw new NNXException("Array cannot be empty."); } var firstNonEmpty = values[firstNonEmptyIndex]; if (firstNonEmpty is double) { var goodValues = new List <double>(values.Length - firstNonEmptyIndex); for (var i = 0; i < values.Length; i++) { var value = values[i]; if (IsEmpty(value)) { continue; } if (value is double) { goodValues.Add((double)value); continue; } if (value is string) { throw new NNXException(inconsistentArrayMessage); } throw new NNXException(string.Format(badTypeMessage, i)); } result = goodValues.ToArray(); } else if (firstNonEmpty is string) { var goodValues = new List <string>(values.Length - firstNonEmptyIndex); for (var i = 0; i < values.Length; i++) { var value = values[i]; if (IsEmpty(value)) { continue; } if (value is string) { goodValues.Add((string)value); continue; } if (value is double) { throw new NNXException(inconsistentArrayMessage); } throw new NNXException(string.Format(badTypeMessage, i)); } result = goodValues.ToArray(); } else { throw new NNXException(string.Format(badTypeMessage, 0)); } ObjectStore.Add(name, result); return(name); }
//[ExcelFunction(Name = "nnMakeObject")] public static string MakeObject(string name, string typeName, object[,] properties) { if (string.IsNullOrEmpty(typeName)) { throw new NNXException("Argument TypeName should not be null or empty."); } Type objectType; if (!SupportedObjects.TryGetValue(typeName, out objectType)) { throw new NNXException($"Unrecognized object type: '{typeName}'."); } var obj = Activator.CreateInstance(objectType); if (properties == null || properties.GetLength(0) == 0) { // No properties to set, we're done here. ObjectStore.Add(name, obj); return(name); } if (properties.GetLength(1) != 2) { throw new NNXException($"Argument Properties must have width 2; was: {properties.GetLength(1)}."); } var numProperties = properties.GetLength(0); var objectProperties = objectType.GetProperties(BindingFlags.Instance | BindingFlags.Public) .Where(p => p.CanWrite).ToList(); for (var i = 0; i < numProperties; i++) { var propertyName = properties[i, 0].ToString(); var value = properties[i, 1]; if (string.IsNullOrEmpty(propertyName)) { throw new NNXException($"Property at position {i + 1} was empty."); } var targetProperty = objectProperties.FirstOrDefault(p => p.Name == propertyName); if (targetProperty == null) { throw new NNXException($"Object type {typeName} does not have property {propertyName}."); } var propertyType = targetProperty.PropertyType; // Special case: assigning an integer double to int. if (propertyType == typeof(int) && value is double && (((double)value) % 1 == 0.0)) { targetProperty.SetValue(obj, (int)((double)value)); continue; } // Special case: assigning int to double. if (propertyType == typeof(double) && value is int) { targetProperty.SetValue(obj, (double)((int)value)); continue; } // Special case: string. if (propertyType == typeof(string)) { var stringValue = value?.ToString() ?? ""; targetProperty.SetValue(obj, stringValue); continue; } // General case. if (propertyType.IsInstanceOfType(value)) { targetProperty.SetValue(obj, value); continue; } // If this was a simple type, then the user provided a value // of the wrong type. if (propertyType.IsAssignableFrom(typeof(int)) || propertyType.IsAssignableFrom(typeof(double)) || propertyType.IsAssignableFrom(typeof(string))) { var propertyTypeName = MapPropertyType(propertyType); var aOrAn = AOrAn(propertyTypeName); throw new NNXException($"Property {propertyName} of object type {typeName} " + $"must be {aOrAn} {propertyTypeName}; was {value}."); } // If we get here, then the target property is an array or array of arrays. var referencedName = properties[i, 1].ToString(); // Special case: weights. if (propertyType.IsAssignableFrom(typeof(double[][]))) { double[][] weights; if (!ObjectStore.TryGet(referencedName, out weights)) { throw new NNXException($"Property {propertyName} of type {typeName} must be of type " + "Weights created using nnMakeWeights() function."); } targetProperty.SetValue(obj, weights); continue; } // Special case: enumerables. if (propertyType.IsAssignableFrom(typeof(string[]))) { string[] array; if (!ObjectStore.TryGet(referencedName, out array)) { throw new NNXException($"Property {propertyName} of type {typeName} must refer " + $"to array containing elements of type string."); } targetProperty.SetValue(obj, array); continue; } if (propertyType.IsAssignableFrom(typeof(double[]))) { double[] array; if (!ObjectStore.TryGet(referencedName, out array)) { throw new NNXException($"Property {propertyName} of type {typeName} must refer " + $"to array containing elements of type number."); } targetProperty.SetValue(obj, array); continue; } if (propertyType.IsAssignableFrom(typeof(int[]))) { int[] intArray; if (ObjectStore.TryGet(referencedName, out intArray)) { targetProperty.SetValue(obj, intArray); continue; } double[] doubleArray; if (ObjectStore.TryGet(referencedName, out doubleArray)) { var convertedArray = new int[doubleArray.Length]; for (var j = 0; j < doubleArray.Length; j++) { var doubleValue = doubleArray[j]; if (doubleValue % 1 != 0) { throw new NNXException($"Property {propertyName} of type {typeName} must refer " + $"to array containing elements of type integer."); } convertedArray[j] = (int)doubleValue; } targetProperty.SetValue(obj, convertedArray); continue; } throw new NNXException($"Property {propertyName} of type {typeName} must refer " + $"to array containing elements of type integer."); } throw new Exception("Reached unreacheable code."); } ObjectStore.Add(name, obj); return(name); }