public static void Extract(IBuildContext context, object obj) { FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic); foreach (FieldInfo field in fields) { object[] attrs = field.GetCustomAttributes(typeof(InjectContextAttribute), true); if (attrs.Length == 0) { continue; } InjectContextAttribute attr = attrs[0] as InjectContextAttribute; if (attr == null || attr.Usage == ContextUsage.In) { continue; } if (field.FieldType == typeof(IBuildContext)) { throw new InvalidOperationException("IBuildContext can only be used with the ContextUsage.In option."); } IContextObject contextObject = field.GetValue(obj) as IContextObject; if (!attr.Optional) { context.SetContextObject(field.FieldType, contextObject); } else if (contextObject != null) { context.SetContextObject(field.FieldType, contextObject); } } }
/// <summary> /// Determines if the input matches any registered scanners, and invokes the scanner callback if a match is found. /// This method will also invoke the <see cref="InputResultDelegate"/> callback if a scanner is found /// </summary> /// <param name="input"></param> /// <param name="ctx"></param> /// <param name="callback"></param> public bool ScanInput(string input, IContextObject ctx, InputResultDelegate callback) { ThrowIfDisposed(); if (_scanners.Count == 0) { return(false); } ScannerData scanner = _scanners.FirstOrDefault(s => s.Pattern.Matches(input)); if (scanner != null) { bool remove = false; object result = scanner.Callback.Invoke(ctx, input, new LightweightParser(ctx), ref remove); callback?.Invoke(InputResult.Scanner, result); if (remove) { _scanners.Remove(scanner); } return(true); } return(false); }
private static void ExtractFields <K>(IContextContainer <K> context, IContextObject extractObj) { List <FieldInfo> fields = cachedTypeFieldDic[extractObj.GetType()][ContextUsage.Extract]; if (fields != null && fields.Count > 0) { foreach (var field in fields) { if (typeof(IContextContainer <>).IsAssignableFrom(field.FieldType)) { throw new InvalidOperationException("Context can only be used with the InjectUsage.In option."); } var attr = field.GetCustomAttribute <ContextIEAttribute>(); object value = field.GetValue(extractObj); if (!attr.Optional) { context.AddOrUpdate((K)attr.Key, value); } else if (value != null) { context.AddOrUpdate((K)attr.Key, value); } } } }
private static void ExtractProperties <K>(IContextContainer <K> context, IContextObject extractObj) { List <PropertyInfo> properties = cachedTypePropertyDic[extractObj.GetType()][ContextUsage.Extract]; if (properties != null && properties.Count > 0) { foreach (var property in properties) { if (typeof(IContextContainer <>).IsAssignableFrom(property.PropertyType)) { throw new InvalidOperationException("Context can only be used with the InjectUsage.In option."); } var attr = property.GetCustomAttribute <ContextIEAttribute>(); object fieldValue = property.GetValue(extractObj); if (!attr.Optional) { context.AddOrUpdate((K)attr.Key, fieldValue); } else if (fieldValue != null) { context.AddOrUpdate((K)attr.Key, fieldValue); } } } }
public EvaluationContext(IContextObject ctxObject, string name = null) { ContextObjects = new List <IContextObject> { ctxObject }; AddNamedContext(ctxObject, name); }
/// <summary> /// Generates a new parser that uses the given registry, args, metadata, context, and ID to run /// </summary> /// <param name="registry">Registry from which the parser will obtain <see cref="IObjectConverter"/>s</param> /// <param name="input">The original input string</param> /// <param name="additionalArgs">Any additional arguments to be added to the end of the argument list</param> /// <param name="metadata">CommandMetadata containing information used to parse and execute</param> /// <param name="exeData"><see cref="CommandExecutorData"/> containing the data required for execution</param> /// <param name="ctx">Context object passed to the executed command, and an <see cref="IObjectConverter"/>s that are used</param> /// <param name="callback">Reference to a method used as a callback when processing completes</param> public Parser(CommandRegistry registry, string input, IEnumerable <object> additionalArgs, CommandMetadata metadata, CommandExecutorData exeData, IContextObject ctx, InputResultDelegate callback) : base(registry, input, additionalArgs, metadata, exeData, ctx, callback) { }
/// <summary> /// Returns an instance of the parser that is currently registered. /// </summary> /// <param name="registry">Registry to be used by the parser</param> /// <param name="input">String input provided to the parser</param> /// <param name="args">Additional arguments to be used by the parser</param> /// <param name="metadata">Metadata to be used by the parser</param> /// <param name="exeData">CommandExecutorData to be used by the parser</param> /// <param name="ctx">Context to be used by the parser</param> /// <param name="callback">Callback method to be invoked when the parser completes</param> public AbstractParser GetParser(CommandRegistry registry, string input, IEnumerable <object> args, CommandMetadata metadata, CommandExecutorData exeData, IContextObject ctx, InputResultDelegate callback) { ThrowIfDisposed(); return((AbstractParser)Activator.CreateInstance(_parser, registry, input, args, metadata, exeData, ctx, callback)); }
/// <summary> /// Adds a command to the command queue, ready to be executed /// </summary> public void QueueInputHandling(string input, IContextObject ctx, InputResultDelegate callback) { ThrowIfDisposed(); if (!ScanInput(input, ctx, callback)) { _queue.Enqueue(new QueueData(input, callback, ctx)); //Set the MRE so that our parser thread knows there's data _mre.Set(); } }
/// <inheritdoc /> public bool TryGetContextObject(Type type, out IContextObject contextObject) { IContextObject cachedContextObject; if (m_ContextObjects.TryGetValue(type, out cachedContextObject) && type.IsInstanceOfType(cachedContextObject)) { contextObject = cachedContextObject; return(true); } contextObject = null; return(false); }
public static void DoRequest <RequestType, ResultType>(this IContextObject sender, RequestType request) where RequestType : IHas <IRequestLogic <RequestType, ResultType> > { var context = sender.Context as IHas <ICRActionLogic <RequestType> >; if (context != null) { context.Enter(request); } else { DefaultContext <RequestType, ResultType> .Instance.Enter(request); } }
public static void DoUnregister <RequestType, ResultType>(this IContextObject sender, Action <RequestType> callBackMethod) where RequestType : IHas <IRequestLogic <RequestType, ResultType> > { var context = sender.Context as ICRModificationLogic <RequestType>; if (context != null) { context.RemovePath(callBackMethod); } else { DefaultContext <RequestType, ResultType> .Instance.RemovePath(callBackMethod); } }
/// <summary> /// Creates an object of the given type, using the given arguments for construction. /// Converters for object types are retrieved from the given registry /// </summary> /// <param name="type"></param> /// <param name="arguments"></param> /// <param name="ctx"></param> /// <returns></returns> public static object CreateObject(Type type, object[] arguments, IContextObject ctx) { string rejectionStr; if (arguments == null) { rejectionStr = $"failed to create an instance of type '{type.Name}' via the default constructor."; } else { rejectionStr = $"failed to create an instance of type '{type.Name}' from arguments '{string.Join(" ", arguments)}'."; } if (type == typeof(string)) { //strings get special treatment - why convert to a string when it already is one? return(string.Join(" ", arguments)); } TypeInfo tInfo = type.GetTypeInfo(); if (tInfo.IsValueType) { try { //value types are converted with a TypeConverter TypeConverter tc = TypeDescriptor.GetConverter(type); return(tc.ConvertFromString(string.Join(" ", arguments))); } catch (Exception e) { throw new CommandParsingException(ParserFailReason.ParsingFailed, $"TypeConverter {rejectionStr}", e); } } if (tInfo.IsArray) { //Arrays get their own method return(CreateArray(type, arguments, ctx)); } try { return(Activator.CreateInstance(type, arguments)); } catch (Exception e) { throw new CommandParsingException(ParserFailReason.ParsingFailed, $"Activator {rejectionStr}", e); } }
/// <inheritdoc /> public void SetContextObject(IContextObject contextObject) { if (contextObject == null) { throw new ArgumentNullException("contextObject"); } List <Type> types = new List <Type>(WalkAssignableTypes(contextObject)); if (types.Count == 0) { throw new Exception($"Could not determine context object type for object of type {contextObject.GetType().FullName}"); } types.ForEach(x => m_ContextObjects[x] = contextObject); }
/// <summary> /// Generates a new parser that uses the given registry, args, metadata, context, and ID to run /// </summary> /// <param name="registry">Registry from which the parser will obtain <see cref="IObjectConverter"/>s</param> /// <param name="input">The original input string</param> /// <param name="additionalArgs">Enumerable of objects to be parsed</param> /// <param name="metadata">CommandMetadata containing information used to parse and execute</param> /// <param name="exeData"><see cref="CommandExecutorData"/> containing the data required for execution</param> /// <param name="ctx">Context object passed to the executed command, and an <see cref="IObjectConverter"/>s that are used</param> /// <param name="callback">Reference to a method to be invoked when parsing completes</param> public AbstractParser(CommandRegistry registry, string input, IEnumerable <object> additionalArgs, CommandMetadata metadata, CommandExecutorData exeData, IContextObject ctx, InputResultDelegate callback) { Registry = registry; Input = input; AdditionalArgs = additionalArgs; Metadata = metadata; ExecutorData = exeData; Context = ctx; Callback = callback; }
/// <summary> /// 设置情景对象 /// </summary> public void SetContextObject(IContextObject contextObject) { if (contextObject == null) { throw new ArgumentNullException("contextObject"); } var type = contextObject.GetType(); if (_contextObjects.ContainsKey(type)) { throw new Exception($"Context object {type} is already existed."); } _contextObjects.Add(type, contextObject); }
/// <inheritdoc /> public void SetContextObject(Type type, IContextObject contextObject) { if (contextObject == null) { throw new ArgumentNullException("contextObject"); } if (!type.IsInterface) { throw new InvalidOperationException(string.Format("Passed in type '{0}' is not an interface.", type)); } if (!type.IsInstanceOfType(contextObject)) { throw new InvalidOperationException(string.Format("'{0}' is not of passed in type '{1}'.", contextObject.GetType(), type)); } m_ContextObjects[type] = contextObject; }
/// <inheritdoc /> public void SetContextObject(IContextObject contextObject) { if (contextObject == null) { throw new ArgumentNullException("contextObject"); } var iCType = typeof(IContextObject); Type[] iTypes = contextObject.GetType().GetInterfaces(); foreach (var iType in iTypes) { if (!iCType.IsAssignableFrom(iType) || iType == iCType) { continue; } m_ContextObjects[iType] = contextObject; } }
/// <inheritdoc /> public void SetContextObject <T>(IContextObject contextObject) where T : IContextObject { if (contextObject == null) { throw new ArgumentNullException("contextObject"); } var type = typeof(T); if (!type.IsInterface) { throw new InvalidOperationException(string.Format("Passed in type '{0}' is not an interface.", type)); } if (!(contextObject is T)) { throw new InvalidOperationException(string.Format("'{0}' is not of passed in type '{1}'.", contextObject.GetType(), type)); } m_ContextObjects[typeof(T)] = contextObject; }
private IEnumerable <Type> WalkAssignableTypes(IContextObject contextObject) { var iCType = typeof(IContextObject); foreach (Type t in contextObject.GetType().GetInterfaces()) { if (iCType.IsAssignableFrom(t) && t != iCType) { yield return(t); } } for (var current = contextObject.GetType(); current != null; current = current.BaseType) { if (iCType.IsAssignableFrom(current) && current != iCType) { yield return(current); } } }
private static void InjectFields <K>(IContextContainer <K> context, IContextObject injectObj) { List <FieldInfo> fields = cachedTypeFieldDic[injectObj.GetType()][ContextUsage.Inject]; if (fields != null && fields.Count > 0) { foreach (var field in fields) { var attr = field.GetCustomAttribute <ContextIEAttribute>(); if (!context.TryGet((K)attr.Key, out object value)) { if (value == null && !attr.Optional) { throw new ContextValueNullException(attr.Key); } } field.SetValue(injectObj, value); } } }
public static void Inject <K>(IContextContainer <K> context, IContextObject injectObj) { if (injectObj == null || context == null) { throw new ArgumentNullException("argument is null."); } Type injectObjType = injectObj.GetType(); if (!cachedTypeFieldDic.ContainsKey(injectObjType)) { CachedFields(injectObjType); } if (!cachedTypePropertyDic.ContainsKey(injectObjType)) { CachedProperties(injectObjType); } InjectFields(context, injectObj); InjectProperties(context, injectObj); }
private static void InjectProperties <K>(IContextContainer <K> context, IContextObject injectObj) { List <PropertyInfo> properties = cachedTypePropertyDic[injectObj.GetType()][ContextUsage.Inject]; if (properties != null && properties.Count > 0) { foreach (var property in properties) { var attr = property.GetCustomAttribute <ContextIEAttribute>(); if (!context.TryGet((K)attr.Key, out object value)) { if (value == null && !attr.Optional) { throw new ContextValueNullException(attr.Key); } } property.SetValue(injectObj, value); } } }
public static void Extract <K>(IContextContainer <K> context, IContextObject extractObj) { if (extractObj == null || context == null) { throw new ArgumentNullException("ContextUtil::Extract->argument is null"); } Type extractObjType = extractObj.GetType(); if (!cachedTypeFieldDic.ContainsKey(extractObjType)) { CachedFields(extractObjType); } if (!cachedTypePropertyDic.ContainsKey(extractObjType)) { CachedProperties(extractObjType); } ExtractFields(context, extractObj); ExtractProperties(context, extractObj); }
public SkillSubContext(NodeMapInfo map, IContextObject owner, IDataScope globalData) : base(map, owner, globalData) { }
public static void DoRequest <RequestType>(this IContextObject sender, RequestType request) where RequestType : IHas <IRequestLogic <RequestType> > { sender.DoRequest <RequestType, bool>(request); }
public static void DoUnregister <RequestType>(this IContextObject sender, Action <RequestType> callBackMethod) where RequestType : IHas <IRequestLogic <RequestType, bool> > { sender.DoUnregister <RequestType, bool>(callBackMethod); }
internal QueueData(string input, InputResultDelegate callback, IContextObject ctx) { Input = input; Callback = callback; Context = ctx; }
private void PipeThreadCallback(string[] inputs, InputResultDelegate callback, IContextObject ctx) { object output = null; for (int i = 0; i < inputs.Length; i++) { string input = $"{inputs[i]}".Trim(); CommandMetadata metadata; lock (_lock) { //Lock the metadata collection, and grab the first metadata that has a matching executor List <CommandMetadata> metadatas = _metadata.Where(m => m.GetFirstOrDefaultExecutorData(input) != null).ToList(); metadata = metadatas.FirstOrDefault(); } if (metadata == null) { //No command matches, so ignore this entire piped input callback.Invoke(InputResult.Unhandled, null); break; } CommandExecutorData exeData = metadata.GetFirstOrDefaultExecutorData(input); RegexString trigger = exeData.ExecutorAttribute.CommandMatcher; input = trigger.RemoveMatchedString(input); object[] arguments = null; if (output != null) { //If there's output from a previous command, append it to the arguments for this command arguments = new[] { output }; } AbstractParser parser; if (i == inputs.Length - 1) { //We only want the final parsing to invoke the parser callback parser = _registry.GetParser(_registry, input, arguments, metadata, exeData, ctx, callback); } else { parser = _registry.GetParser(_registry, input, arguments, metadata, exeData, ctx, null); } //Threads are joined for synchronous behaviour. Running each command concurrently (and thus potentially out of order) will not work here. Thread thread = parser.GetThread(); thread.Start(); thread.Join(); //Set output so that it's appended to the end of the next input output = parser.Output; } }
public override IContext createContext(NodeMapInfo map, IContextObject owner, IDataScope globalData) { return(new SkillSubContext(map, owner, globalData)); }
/// <summary> /// Creates an array of the given type from the given arguments /// </summary> /// <param name="type"></param> /// <param name="arguments"></param> /// <param name="ctx"></param> /// <returns></returns> public static object CreateArray(Type type, object[] arguments, IContextObject ctx) { Type elementType = type.GetElementType(); IObjectConverter converter = ctx.Registry.GetConverter(elementType); string failedConvert = $"Failed to convert '{string.Join(" ", arguments)}' to Type {type.Name}."; string failedCreate = $"failed to create an instance of type {elementType.Name} from argument "; //Create the generic array of the required size Array array = (Array)Activator.CreateInstance(type, arguments.Length); for (int i = 0; i < array.Length; i++) { if (converter != null) { //if we have a converter, use it object conversion = converter.ConvertFromString(arguments[i].ToString(), ctx); if (conversion == null) { throw new CommandParsingException( ParserFailReason.ParsingFailed, failedConvert, new Exception($"Conversion failed by '{converter.GetType().Name}.'") ); } array.SetValue(conversion, i); continue; } if (elementType == typeof(string)) { //strings are special, so have special treatment array.SetValue(arguments[i], i); continue; } if (elementType.GetTypeInfo().IsValueType) { //value types can be created with a typeconverter TypeConverter tc = TypeDescriptor.GetConverter(type.GetElementType()); try { //but a bad argument will throw an exception, so handle that array.SetValue(tc.ConvertFrom(arguments[i]), i); } catch (Exception e) { throw new CommandParsingException(ParserFailReason.ParsingFailed, $"TypeConverter {failedCreate} '{arguments[i]}'.", e); } } else { //reference types need to be created with the Activator try { //once again, bad arguments can throw an exception object element = Activator.CreateInstance(elementType, arguments[i]); array.SetValue(element, i); } catch (Exception e) { throw new CommandParsingException(ParserFailReason.ParsingFailed, $"Activator {failedCreate} '{arguments[i]}'.", e); } } } return(array); }