public void GetMetadata_GetsMetadata() { var commandParameterAttribute = new CommandParameterAttribute( 0, "Arg0", typeof(Resources), "TestResource") { Required = false, DefaultValue = "Default" }; var targetProperty = typeof(CommandStub) .GetProperty(nameof(CommandStub.StringProperty)); var commandParameterMetadata = commandParameterAttribute.GetMetadata(targetProperty); Assert.That(commandParameterMetadata.Index, Is.EqualTo(0)); Assert.That(commandParameterMetadata.Name, Is.EqualTo("Arg0")); Assert.That(commandParameterMetadata.HelpText, Is.EqualTo("This is a test resource.")); Assert.That(commandParameterMetadata.Required, Is.False); Assert.That(commandParameterMetadata.DefaultValue, Is.EqualTo("Default")); Assert.That(commandParameterMetadata.Converter, Is.Not.Null); Assert.That(commandParameterMetadata.Converter, Is.TypeOf <DefaultArgumentConverter>()); Assert.That(commandParameterMetadata.PropertyInfo, Is.EqualTo(targetProperty)); }
/// <summary> /// 获得存储过程参数 /// </summary> /// <returns></returns> public IDbParms GetParameters() { SqlParameterProvider parameters = new SqlParameterProvider(); var properties = this.GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); foreach (var p in properties) { CommandParameterAttribute attr = (CommandParameterAttribute)p.GetCustomAttributes(typeof(CommandParameterAttribute), false).FirstOrDefault(); if (attr == null) { continue; } string SPName = attr.SPName; if (String.IsNullOrWhiteSpace(SPName)) { SPName = p.Name; } object value = p.GetValue(this, null); parameters.AddParameter("@" + SPName, attr.DbType, attr.Size, value, attr.Direction); } return(parameters); }
/// <summary> /// Find a paramater's target in code (methods) /// </summary> /// <param name="commandType">the system type of the command</param> /// <param name="currentNeededParm">the paramater we are after</param> public void SeekInCode(Type commandType, CommandParameterAttribute currentNeededParm) { var validTargetTypes = commandsAssembly.GetTypes().Where(t => t.GetInterfaces().Contains(currentNeededParm.ParameterType)); var internalCommandString = CommandStringRemainder.ToList(); var parmWords = internalCommandString.Count(); Type parm = null; while (parmWords > 0) { var currentParmString = string.Join(" ", RemoveGrammaticalNiceities(internalCommandString.Take(parmWords))).ToLower(); if (!currentNeededParm.MatchesPattern(currentParmString)) { parmWords--; continue; } var validParms = validTargetTypes.Where(comm => comm.GetCustomAttributes <CommandKeywordAttribute>() .Any(att => att.Keyword.Equals(currentParmString))); if (validParms.Count() > 1) { AccessErrors.Add(string.Format("There are {0} potential targets with that name for the {1} command.", validParms.Count(), commandType.Name)); AccessErrors.AddRange(validParms.Select(typ => typ.Name)); break; } else if (validParms.Count() == 1) { parm = validParms.First(); if (parm != null) { switch (currentNeededParm.Usage) { case CommandUsage.Supporting: Supporting = Activator.CreateInstance(parm); break; case CommandUsage.Subject: Subject = Activator.CreateInstance(parm); break; case CommandUsage.Target: Target = Activator.CreateInstance(parm); break; } } CommandStringRemainder = CommandStringRemainder.Skip(parmWords); return; } parmWords--; } }
/// <summary> /// Find a parameter target in backing data /// </summary> /// <typeparam name="T">the system type of the data</typeparam> /// <param name="commandType">the system type of the command</param> /// <param name="currentNeededParm">the conditions for the parameter we're after</param> public void SeekInBackingData <T>(Type commandType, CommandParameterAttribute currentNeededParm) where T : IData { var internalCommandString = CommandStringRemainder.ToList(); var parmWords = internalCommandString.Count(); while (parmWords > 0) { var currentParmString = string.Join(" ", internalCommandString.Take(parmWords)); if (!currentNeededParm.MatchesPattern(currentParmString)) { parmWords--; continue; } var validObject = default(T); long parmID = -1; if (!long.TryParse(currentParmString, out parmID)) { validObject = DataWrapper.GetOneBySharedKey <T>("Name", currentParmString); } else { validObject = DataWrapper.GetOne <T>(parmID); } if (validObject != null && !validObject.Equals(default(T))) { switch (currentNeededParm.Usage) { case CommandUsage.Supporting: Supporting = validObject; break; case CommandUsage.Subject: Subject = validObject; break; case CommandUsage.Target: Target = validObject; break; } CommandStringRemainder = CommandStringRemainder.Skip(parmWords); return; } parmWords--; } }
/// <summary> /// Ensures the given parameters follow the parameter rules /// </summary> /// <exception cref="CommandParsingException">Thrown if a parameter does not follow command parameter rules</exception> public void CheckParameterStructure(CommandExecutorData executor, IEnumerable<ParameterInfo> parameters) { bool optionalFound = false; bool unknownLengthFound = false; requiredArgumentCount = 0; Dictionary<ParameterInfo, CommandParameterAttribute> paramData = new Dictionary<ParameterInfo, CommandParameterAttribute>(); foreach (ParameterInfo param in parameters) { CommandParameterAttribute attr = param.GetCustomAttribute<CommandParameterAttribute>(); if (attr == null) { attr = new CommandParameterAttribute(param.IsOptional); } paramData.Add(param, attr); if (optionalFound && !attr.Optional) { throw new CommandParsingException( ParserFailReason.InvalidParameter, $"Parameter '{param.Name}' is required, but follows an optional parameter." ); } if (unknownLengthFound) { throw new CommandParsingException( ParserFailReason.InvalidParameter, $"Parameter '{param.Name}' follows an unknown-length parameter." ); } if (attr.Optional) { optionalFound = true; } if (attr.Repetitions < 1) { unknownLengthFound = true; requiredArgumentCount = -1; } if (!attr.Optional) { requiredArgumentCount += attr.Repetitions; } } executor.ParameterData = paramData; }
public void DisplayDescription(string cmd) { if (string.IsNullOrEmpty(cmd)) { return; } cmd = cmd.ToLower(); if (CommandsList.ContainsKey(cmd) == false) { log.ErrorFormat("The command of '{0}' is not exists.", cmd); return; } ICommand command = CommandsList[cmd]; object[] attrs = command.GetType().GetCustomAttributes(typeof(CommandAttribute), false); if (attrs.Length > 0) { CommandAttribute ca = attrs[0] as CommandAttribute; if (!string.IsNullOrEmpty(ca.Description)) { WriteLine(0, ca.Cmd + ": ", ca.Cmd.Length + 2, ca.Description); } if (!string.IsNullOrEmpty(ca.Usage)) { WriteLine(0, "用法:", 0, ca.Usage + "\r\n"); } } attrs = command.GetType().GetCustomAttributes(typeof(CommandParameterAttribute), false); WriteLine(4, "/?", 10, "显示帮助信息"); for (int i = 0; i < attrs.Length; i++) { CommandParameterAttribute cpa = attrs[i] as CommandParameterAttribute; WriteLine(4, cpa.Key, 10, cpa.Description); } Console.WriteLine(); }
public void Constructor_GetsValues() { var commandParameterAttribute = new CommandParameterAttribute( 0, "Arg0", typeof(Resources), "TestResource") { Required = false, DefaultValue = "Default" }; Assert.That(commandParameterAttribute.Index, Is.EqualTo(0)); Assert.That(commandParameterAttribute.Name, Is.EqualTo("Arg0")); Assert.That(commandParameterAttribute.HelpText, Is.EqualTo("This is a test resource.")); Assert.That(commandParameterAttribute.Required, Is.False); Assert.That(commandParameterAttribute.DefaultValue, Is.EqualTo("Default")); }
/// <summary> /// Find a parameter target in reference data /// </summary> /// <typeparam name="T">the system type of the data</typeparam> /// <param name="commandType">the system type of the command</param> /// <param name="currentNeededParm">the conditions for the parameter we're after</param> public void SeekInReferenceData <T>(Type commandType, CommandParameterAttribute currentNeededParm) where T : IReferenceData { var internalCommandString = CommandStringRemainder.ToList(); var parmWords = internalCommandString.Count(); while (parmWords > 0) { var currentParmString = string.Join(" ", RemoveGrammaticalNiceities(internalCommandString.Take(parmWords))); if (!currentNeededParm.MatchesPattern(currentParmString)) { parmWords--; continue; } var validObject = ReferenceWrapper.GetOne <T>(currentParmString); if (validObject != null && !validObject.Equals(default(T))) { switch (currentNeededParm.Usage) { case CommandUsage.Supporting: Supporting = validObject; break; case CommandUsage.Subject: Subject = validObject; break; case CommandUsage.Target: Target = validObject; break; } CommandStringRemainder = CommandStringRemainder.Skip(parmWords); return; } parmWords--; } }
public bool Conforms(CommandParameterAttribute attr) { var name = this.IsNamed && attr.Id == this.Name; var index = this.IsIndexed && attr.Index == this.Index; var value = string.IsNullOrEmpty(attr.Value) || attr.Value == this.Value; var type = false; try { if (this.Value != null) { var test = Convert.ChangeType(this.Value, attr.Type); } type = true; } catch (Exception) { } return (!IsNamed || name) && (!IsIndexed || index) && value && type; }
public bool Conforms(CommandParameterAttribute attr) { var name = this.IsNamed && attr.Id == this.Name; var index = this.IsIndexed && attr.Index == this.Index; var value = string.IsNullOrEmpty(attr.Value) || attr.Value == this.Value; var type = false; try { if (this.Value != null) { var test = Convert.ChangeType(this.Value, attr.Type); } type = true; } catch (Exception) { } return((!IsNamed || name) && (!IsIndexed || index) && value && type); }
private bool ValidateRecursive(object obj, bool throwException, int deepLevel) { const int maxDeepLevel = 100; // Prevent "StackOverflowException" (this should never happen) if (++deepLevel == maxDeepLevel) { throw new InvalidOperationException("Recursive function call exceeded the permitted deep level."); } // Validate all properties with "CommandParameterAttribute" foreach (var property in CommandParameterAttribute.GetOrderedProperties(obj)) { // If property is value type and is not nullable, than must be set to nullable if (property.PropertyType.IsValueType && Nullable.GetUnderlyingType(property.PropertyType) == null) { if (throwException) { throw new InvalidOperationException($"'{property.Name}' property must be nullable."); } return(false); } } // Validate all properties with attributes derived from "ValidationAttribute" var results = new List <ValidationResult>(); Validator.TryValidateObject(obj, new ValidationContext(obj), results, true); if (results.Count > 0) { if (throwException) { throw new ArgumentException(results[0].ToString()); } return(false); } // Find all properties value with 'CommandBuilderObjectAttribute' and validate it recursively var properties = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); foreach (var property in properties) { var propertyValue = property.GetValue(obj); if (propertyValue == null) { continue; } if (propertyValue.GetType().GetCustomAttribute <CommandBuilderObjectAttribute>() != null) { ValidateRecursive(propertyValue, throwException, deepLevel); } } return(true); }
private string BuildStringRecursive(object obj, int deepLevel) { const int maxDeepLevel = 100; // Prevent "StackOverflowException" (this should never happen) if (++deepLevel == maxDeepLevel) { throw new InvalidOperationException("Recursive function call exceeded the permitted deep level."); } var finalString = new StringBuilder(); // Loop through all properties with "CommandParameterAttribute" attribute foreach (var property in CommandParameterAttribute.GetOrderedProperties(obj)) { // Get property value var propertyValue = property.GetValue(obj); if (propertyValue == null) { continue; } // Check if property value can be included in final command string if (!CanIncludeProperty(obj, property)) { continue; } // if property value has 'CommandBuilderObjectAttribute' then build string from it recursively if (propertyValue.GetType().GetCustomAttribute <CommandBuilderObjectAttribute>() != null) { var value = BuildStringRecursive(propertyValue, deepLevel); if (!string.IsNullOrWhiteSpace(value)) { finalString.Append($" {value}"); } continue; } // Get "CommandParameterAttribute" from property var commandParameterAttribute = property.GetCustomAttribute <CommandParameterAttribute>(); if (!commandParameterAttribute.RemoveWhiteSpaceBeforeValue) { finalString.Append(" "); } var convertedPropertyValue = GetConvertedPropertyValue(obj, property); // If value format is set in "CommandParameterAttribute", then use it to format property value if (!string.IsNullOrWhiteSpace(commandParameterAttribute.Format)) { finalString.Append(string.Format(commandParameterAttribute.Format, convertedPropertyValue)); } else { finalString.Append($"{convertedPropertyValue}"); } } return(finalString.ToString().Trim()); }
/// <summary> /// Find a parameter target in the live world (entity) /// </summary> /// <typeparam name="T">the system type of the entity</typeparam> /// <param name="commandType">the system type of the command</param> /// <param name="currentNeededParm">the conditions for the parameter we're after</param> public void SeekInLiveWorldContainer <T>(Type commandType, CommandParameterAttribute currentNeededParm, Type subjectType) { //Borked it here, we found nothing viable earlier if (Subject == null || !((ICollection <IEntity>)Subject).Any()) { return; } var subjectCollection = (ICollection <IEntity>)Subject; //Containers are touch range only var internalCommandString = CommandStringRemainder.ToList(); var disambiguator = -1; var parmWords = internalCommandString.Count(); while (parmWords > 0) { var currentParmString = string.Join(" ", RemoveGrammaticalNiceities(internalCommandString.Take(parmWords))).ToLower(); //We have disambiguation here, we need to pick the first object we get back in the list if (Regex.IsMatch(currentParmString, LiveWorldDisambiguationSyntax)) { disambiguator = int.Parse(currentParmString.Substring(0, currentParmString.IndexOf("."))); currentParmString = currentParmString.Substring(currentParmString.IndexOf(".") + 1); } if (!currentNeededParm.MatchesPattern(currentParmString)) { parmWords--; continue; } var validObjects = new List <T>(); validObjects.AddRange(subjectCollection.Select(sbj => sbj.CurrentLocation) .Where(cl => cl.Keywords.Any(key => key.Contains(currentParmString))).Select(ent => (T)ent)); if (validObjects.Count() > 0) { //Skip everything up to the right guy and then take the one we want so we don't have to horribly alter the following logic flows if (disambiguator > -1 && validObjects.Count() > 1) { validObjects = validObjects.Skip(disambiguator - 1).Take(1).ToList(); } if (validObjects.Count() > 1) { AccessErrors.Add(string.Format("There are {0} potential containers with that name for the {1} command. Try using one of the following disambiguators:", validObjects.Count(), commandType.Name)); int iterator = 1; foreach (var obj in validObjects) { var entityObject = (IEntity)obj; AccessErrors.Add(string.Format("{0}.{1}", iterator++, entityObject.DataTemplate.Name)); } break; } else if (validObjects.Count() == 1) { var parm = validObjects.First(); if (parm != null) { switch (currentNeededParm.Usage) { case CommandUsage.Supporting: Supporting = parm; break; case CommandUsage.Subject: Subject = parm; break; case CommandUsage.Target: Target = parm; break; } } CommandStringRemainder = CommandStringRemainder.Skip(parmWords); //Now try to set the subject var container = (IContains)parm; var validSubjects = new List <IEntity>(); validSubjects.AddRange(subjectCollection.Where(sbj => sbj.CurrentLocation.Equals(container))); if (validSubjects.Count() > 1) { AccessErrors.Add(string.Format("There are {0} potential targets with that name inside {1} for the {2} command. Try using one of the following disambiguators:" , validObjects.Count(), parmWords, commandType.Name)); int iterator = 1; foreach (var obj in validSubjects) { AccessErrors.Add(string.Format("{0}.{1}", iterator++, obj.DataTemplate.Name)); } } else if (validObjects.Count() == 1) { Subject = validSubjects.First(); } return; } } parmWords--; } }
/// <summary> /// Find a parameter target in the live world (entity) /// </summary> /// <typeparam name="T">the system type of the entity</typeparam> /// <param name="commandType">the system type of the command</param> /// <param name="currentNeededParm">the conditions for the parameter we're after</param> /// <param name="hasContainer">does the command need a container to look for things in</param> /// <param name="seekRange">how far we can look</param> public void SeekInLiveWorld <T>(Type commandType, CommandParameterAttribute currentNeededParm, CommandRangeAttribute seekRange, bool hasContainer) { var internalCommandString = CommandStringRemainder.ToList(); var disambiguator = -1; var parmWords = internalCommandString.Count(); while (parmWords > 0) { var currentParmString = string.Join(" ", RemoveGrammaticalNiceities(internalCommandString.Take(parmWords))).ToLower(); //We have disambiguation here, we need to pick the first object we get back in the list if (Regex.IsMatch(currentParmString, LiveWorldDisambiguationSyntax)) { disambiguator = int.Parse(currentParmString.Substring(0, currentParmString.IndexOf("."))); currentParmString = currentParmString.Substring(currentParmString.IndexOf(".") + 1); } if (!currentNeededParm.MatchesPattern(currentParmString)) { parmWords--; continue; } var validObjects = new List <T>(); switch (seekRange.Type) { case CommandRangeType.Self: validObjects.Add((T)Actor); break; case CommandRangeType.Touch: validObjects.AddRange(Location.GetContents <T>().Where(ent => ((IEntity)ent).Keywords.Any(key => key.Contains(currentParmString)))); if (Actor.GetType().GetInterfaces().Any(typ => typ == typeof(IContains))) { validObjects.AddRange(((IContains)Actor).GetContents <T>().Where(ent => ((IEntity)ent).Keywords.Any(key => key.Contains(currentParmString)))); } //Containers only matter for touch usage subject paramaters, actor's inventory is already handled //Don't sift through another intelligence's stuff //TODO: write "does entity have permission to another entity's inventories" function on IEntity if (hasContainer && currentNeededParm.Usage == CommandUsage.Subject) { foreach (IContains thing in Location.GetContents <T>().Where(ent => ent.GetType().GetInterfaces().Any(intf => intf == typeof(IContains)) && !ent.GetType().GetInterfaces().Any(intf => intf == typeof(IMobile)) && !ent.Equals(Actor))) { validObjects.AddRange(thing.GetContents <T>().Where(ent => ((IEntity)ent).Keywords.Any(key => key.Contains(currentParmString)))); } } break; case CommandRangeType.Local: //requires Range to be working break; case CommandRangeType.Regional: //requires range to be working break; case CommandRangeType.Global: validObjects.AddRange(LiveCache.GetAll <T>().Where(ent => ((IEntity)ent).Keywords.Any(key => key.Contains(currentParmString)))); break; } if (hasContainer && currentNeededParm.Usage == CommandUsage.Subject && validObjects.Count() > 0) { Subject = validObjects; CommandStringRemainder = CommandStringRemainder.Skip(parmWords); return; } else if (validObjects.Count() > 0) { //Skip everything up to the right guy and then take the one we want so we don't have to horribly alter the following logic flows if (disambiguator > -1 && validObjects.Count() > 1) { validObjects = validObjects.Skip(disambiguator - 1).Take(1).ToList(); } if (validObjects.Count() > 1) { AccessErrors.Add(string.Format("There are {0} potential targets with that name for the {1} command. Try using one of the following disambiguators:", validObjects.Count(), commandType.Name)); int iterator = 1; foreach (var obj in validObjects) { var entityObject = (IEntity)obj; AccessErrors.Add(string.Format("{0}.{1}", iterator++, entityObject.DataTemplate.Name)); } break; } else if (validObjects.Count() == 1) { var parm = validObjects.First(); if (parm != null) { switch (currentNeededParm.Usage) { case CommandUsage.Supporting: Supporting = parm; break; case CommandUsage.Subject: Subject = parm; break; case CommandUsage.Target: Target = parm; break; } } CommandStringRemainder = CommandStringRemainder.Skip(parmWords); return; } } parmWords--; } }