/// <summary> /// Unwraps the TargetInvocationException that reflection methods helpfully give us. /// </summary> /// <param name="tie">Exception to unwrap</param> /// <returns>A copy of the inner exception, for a few cases.</returns> public static Exception UnwrapTargetInvokationException(TargetInvocationException tie) { if (tie.InnerException.GetType() == typeof(DataStoreCastException)) { DataStoreCastException orig = (DataStoreCastException)tie.InnerException; return(new DataStoreCastException(orig.FromType, orig.ToType, tie)); } else if (tie.InnerException.GetType() == typeof(DataNode.ValueNotInitialized)) { DataNode.ValueNotInitialized orig = (DataNode.ValueNotInitialized)tie.InnerException; throw new DataNode.ValueNotInitialized(orig.key, tie); } else if (tie.InnerException.GetType() == typeof(NotSupportedException)) { NotSupportedException orig = (NotSupportedException)tie.InnerException; throw new NotSupportedException(orig.Message, tie); } return(null); }
/// <summary> /// Attempts to parse a value from the config node. Returns a default value if not found. /// Validates return values using the given function. /// </summary> /// <typeparam name="T">The type of value to convert to.</typeparam> /// <param name="configNode">The ConfigNode to read from.</param> /// <param name="key">The key to examine.</param> /// <param name="setter">Function used to set the output value</param> /// <param name="obj">Factory object for error messages.</param> /// <param name="defaultValue">Default value to use if there is no key in the config node</param> /// <param name="validation">Validation function to run against the returned value</param> /// <returns>The parsed value (or default value if not found)</returns> public static bool ParseValue <T>(ConfigNode configNode, string key, Action <T> setter, IContractConfiguratorFactory obj, T defaultValue, Func <T, bool> validation) { // Initialize the data type of the expression if (currentDataNode != null && !currentDataNode.IsInitialized(key)) { currentDataNode.BlankInit(key, typeof(T)); } bool valid = true; T value = defaultValue; if (configNode.HasValue(key) || configNode.HasNode(key)) { try { // Check whether there's a value if (configNode.HasValue(key) && string.IsNullOrEmpty(configNode.GetValue(key))) { LoggingUtil.LogError(obj, obj.ErrorPrefix(configNode) + ": Required value '" + key + "' is empty."); valid = false; } else { // Load value value = ParseValue <T>(configNode, key, true); } // If value was non-null, run validation if (value != null && (typeof(T) != typeof(string) || ((string)(object)value) != "")) { try { valid = validation.Invoke(value); if (!valid) { // In general, the validation function should throw an exception and give a much better message LoggingUtil.LogError(obj, obj.ErrorPrefix(configNode) + ": A validation error occured while loading the key '" + key + "' with value '" + value + "'."); } } catch (Exception e) { if (e is DataNode.ValueNotInitialized) { throw; } LoggingUtil.LogError(obj, obj.ErrorPrefix(configNode) + ": A validation error occured while loading the key '" + key + "' with value '" + value + "'."); LoggingUtil.LogException(e); valid = false; } } } catch (Exception e) { if (e.GetType() == typeof(DataNode.ValueNotInitialized)) { string dependency = ((DataNode.ValueNotInitialized)e).key; string path = currentDataNode.Path() + key; LoggingUtil.LogVerbose(typeof(ConfigNodeUtil), "Trying to load " + path + ", but " + dependency + " is uninitialized."); // Defer loading this value DeferredLoadObject <T> loadObj = null; if (!deferredLoads.ContainsKey(path) || deferredLoads[path].GetType().GetGenericArguments().First() != typeof(T)) { deferredLoads[path] = new DeferredLoadObject <T>(configNode, key, setter, obj, validation, currentDataNode); } loadObj = (DeferredLoadObject <T>)deferredLoads[path]; // New dependency - try again if (!loadObj.dependencies.Contains(dependency)) { LoggingUtil.LogVerbose(typeof(ConfigNodeUtil), " New dependency, will re-attempt to load later."); loadObj.dependencies.Add(dependency); return(true); } } LoggingUtil.LogError(obj, obj.ErrorPrefix(configNode) + ": Error parsing " + key); // Return immediately on deferred load error if (e.GetType() == typeof(DataNode.ValueNotInitialized)) { DataNode.ValueNotInitialized vni = e as DataNode.ValueNotInitialized; LoggingUtil.LogException(new Exception("Unknown identifier '@" + vni.key + "'.")); return(false); } LoggingUtil.LogException(e); valid = false; } finally { AddFoundKey(configNode, key); } } // Store the value if (currentDataNode != null) { currentDataNode[key] = value; if (!currentDataNode.IsDeterministic(key) && initialLoad) { currentDataNode.DeferredLoads.Add(new DeferredLoadObject <T>(configNode, key, setter, obj, validation, currentDataNode)); } } // Invoke the setter function if (valid) { setter.Invoke(value); } return(valid); }