Exemple #1
0
        /// <summary>
        /// Set the value of a property on this object at the specified path
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="path">The path, consisting of property names and sub-property names
        /// separated by '.' characters.  For example: 'PropertyName.SubPropertyName.SubSubPropertyName' etc.
        /// Parameterless methods may also be invoked by adding '()', i.e.:
        /// 'PropertyName.SubMethodName().SubSubPropertyName'.
        /// Methods and properties on the optional context object may also be invoked in the same way, via a
        /// '*' redirection.  For example: '*.MethodName()'.  When switching to the context
        /// object the SetSourceObject method on it will be called and the current object or property value
        /// passed in.  This allows for complex operations to be performed in order to return a value
        /// provided that functionality is implemented in a suitable context object provided.</param>
        /// <param name="value">The value to be assigned to the property</param>
        /// <param name="context">The (optional) string conversion context object.  If supplies this allows
        /// the '*' symbol to be used within property paths in order to access properties and
        /// functions supplied on the context object.</param>
        public static void SetByPath(this object obj, string path, object value, IStringConversionContext context = null)
        {
            object setOn = obj;
            int    iLast = path.LastIndexOf('.');

            if (iLast > 0)
            {
                string rootPath = path.Substring(0, iLast);
                setOn = obj.GetFromPath(rootPath, context);
                path  = path.Substring(iLast + 1);
            }
            if (setOn != null)
            {
                PropertyInfo pInfo = setOn.GetType().GetProperty(path);
                if (value != null && value is IConvertible && !pInfo.PropertyType.IsAssignableFrom(value.GetType()))
                {
                    value = Convert.ChangeType(value, pInfo.PropertyType);
                }
                pInfo.SetValue(setOn, value);
            }
        }
Exemple #2
0
 /// <summary>
 /// Format constructor
 /// </summary>
 /// <param name="format"></param>
 public DocumentTextSerialiser(TextFormat format, IStringConversionContext context = null) : base(format, context)
 {
 }
Exemple #3
0
        /// <summary>
        /// Generate a formatted string which represents the object or a subcomponent of it
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="format"></param>
        /// <param name="openTag"></param>
        /// <param name="closeTag"></param>
        /// <param name="context"></param>
        /// <param name="resultBuilder"></param>
        /// <param name="pathBuilder"></param>
        private static void CreateFormattedString(this object obj, string format, char openTag, char closeTag,
                                                  string ifTag, string thenTag, IStringConversionContext context, StringBuilder resultBuilder, StringBuilder pathBuilder)
        {
            int tagLevel = 0;

            //IF stages:
            const int NO_IFS       = 0; //Not current in a conditional
            const int IF_CONDITION = 1; //Parsing the condition
            const int IF_TRUE      = 2; //If statement is true
            const int IF_FALSE     = 3; //If statement is false

            int ifLevel = NO_IFS;

            for (int i = 0; i < format.Length; i++)
            {
                char c = format[i];

                if (ifTag != null && format.AppearsAt(i, ifTag))
                {
                    i += ifTag.Length - 1; //Jump forward
                    if (ifLevel != NO_IFS)
                    {
                        ifLevel = NO_IFS; //Close if
                    }
                    else
                    {
                        ifLevel = IF_CONDITION; //Open if
                        //tagLevel++; //Look to recieve a value
                    }
                }
                else if (ifLevel == NO_IFS || ifLevel == IF_TRUE)
                {
                    if (c == openTag)
                    {
                        tagLevel++;               // Open tag
                    }
                    //TODO: End of line
                    else if (c == closeTag && tagLevel > 0) // Close tag
                    {
                        tagLevel--;
                        if (tagLevel == 0)
                        {
                            resultBuilder.Append(obj.GetFromPath(pathBuilder.ToString(), context));
                            pathBuilder.Clear();
                        }
                    }
                    else if (tagLevel == 0) //Use text verbatim
                    {
                        resultBuilder.Append(c);
                    }
                    else //Tags open
                    {
                        pathBuilder.Append(c);
                    }
                }
                else if (ifLevel == IF_CONDITION)
                {
                    if (format.AppearsAt(i, thenTag))
                    {
                        string expression = pathBuilder.ToString().Trim();
                        pathBuilder.Clear();
                        //Invert via the '!' operator
                        bool invert = false;
                        if (expression.StartsWith("!"))
                        {
                            invert     = true;
                            expression = expression.TrimStart('!');
                        }
                        object condition = obj.GetFromPath(expression, context);

                        if ((condition == null || (condition is bool && !(bool)condition)) != invert)
                        {
                            // Condition is null or false - do not write
                            ifLevel = IF_FALSE;
                        }
                        else
                        {
                            // Condition is true or non-null
                            ifLevel = IF_TRUE;
                        }
                    }
                    else
                    {
                        pathBuilder.Append(c);
                    }
                }

                //End conditionals after a newline
                if (ifLevel != NO_IFS && c == '\n')
                {
                    ifLevel = NO_IFS;
                }
            }
        }
Exemple #4
0
        /// <summary>
        /// Convert this object to a string in the specified format.
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="format">The format to be used to construct the text string.
        /// This should take the form of a string interspersed with property paths surrounded by
        /// open and close tag characters, the values of which will be inserted into the text.
        /// For example "The value of the subproperty is: {PropertyName.SubPropertyName}"</param>
        /// <param name="openTag">The opening tag for specifying property paths.  Default is '{'.</param>
        /// <param name="closeTag">The closing tag for specifying property paths.  Default is '}'.</param>
        /// <param name="context">The (optional) string conversion context object.  If supplies this allows
        /// the '*' symbol to be used within property paths in order to access properties and
        /// functions supplied on the context object.</param>
        /// <returns></returns>
        public static string ToString(this object obj, string format, char openTag = '{', char closeTag = '}',
                                      string ifTag = TextFormat.IF, string thenTag = TextFormat.THEN, IStringConversionContext context = null)
        {
            StringBuilder resultBuilder = new StringBuilder();

            StringBuilder pathBuilder = new StringBuilder();

            context.SubComponentIndex = 0;

            if (context.HasSubComponentsToWrite(obj))
            {
                int oldIndex = context.SubComponentIndex;
                //Sub-items:
                while (context.HasSubComponentsToWrite(obj))
                {
                    CreateFormattedString(obj, format, openTag, closeTag,
                                          ifTag, thenTag, context, resultBuilder, pathBuilder);
                    resultBuilder.AppendLine();
                    context.SubComponentIndex++;
                }
                context.SubComponentIndex = oldIndex;
            }
            else
            {
                CreateFormattedString(obj, format, openTag, closeTag,
                                      ifTag, thenTag, context, resultBuilder, pathBuilder);
            }

            return(resultBuilder.ToString());
        }
Exemple #5
0
        /// <summary>
        /// Get the value of a property on this object at the specified path
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="path">The path, consisting of property names and sub-property names
        /// separated by '.' characters.  For example: 'PropertyName.SubPropertyName.SubSubPropertyName' etc.
        /// Parameterless methods may also be invoked by adding '()', i.e.:
        /// 'PropertyName.SubMethodName().SubSubPropertyName'.
        /// Methods and properties on the optional context object may also be invoked in the same way, via a
        /// '*' redirection.  For example: '*.MethodName()'.  When switching to the context
        /// object the SetSourceObject method on it will be called and the current object or property value
        /// passed in.  This allows for complex operations to be performed in order to return a value
        /// provided that functionality is implemented in a suitable context object provided.</param>
        /// <param name="context">The (optional) string conversion context object.  If supplies this allows
        /// the '*' symbol to be used within property paths in order to access properties and
        /// functions supplied on the context object.</param>
        /// <returns></returns>
        public static object GetFromPath(this object obj, string path, IStringConversionContext context = null)
        {
            foreach (string substring in path.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries))
            {
                string token = substring;
                if (obj == null)
                {
                    return(null);
                }

                Type type = obj.GetType();

                if (token.EqualsIgnoreCase(TextFormat.CONTEXT))
                {
                    context.SetSourceObject(obj);
                    obj = context;
                }
                else if (token.EndsWith("()")) // Method
                {
                    MethodInfo info = type.GetMethod(token.TrimEnd(')', '('), new Type[] { });
                    if (info == null)
                    {
                        return(null);
                    }
                    else
                    {
                        obj = info.Invoke(obj, null);
                    }
                }
                else // Property...
                {
                    PropertyInfo info;
                    string       key = null;
                    if (token.EndsWith("]"))
                    {
                        token = token.TrimEnd(']');
                        int keyStart = token.LastIndexOf('[');
                        if (keyStart >= 0)
                        {
                            key   = token.Substring(keyStart + 1);
                            token = token.Substring(0, keyStart);
                            if (keyStart == 0)
                            {
                                token = "Item";
                            }
                        }
                    }
                    if (key != null)
                    {
                        info = type.GetProperty(token, new Type[] { key.GetType() });
                        if (info == null)
                        {
                            //Property accessor isn't indexed, but maybe the object itself is...
                            info = type.GetProperty(token);
                            if (info != null)
                            {
                                obj = info.GetValue(obj, null);
                                if (obj != null)
                                {
                                    info = obj.GetType().GetProperty("Item", new Type[] { key.GetType() });
                                }
                            }
                        }
                    }
                    else
                    {
                        info = type.GetProperty(token);
                    }
                    if (info == null)
                    {
                        //...or Field?
                        FieldInfo fInfo = type.GetField(token);
                        if (fInfo == null)
                        {
                            return(null);
                        }
                        else
                        {
                            obj = fInfo.GetValue(obj);
                        }
                    }
                    else
                    {
                        if (key != null)
                        {
                            obj = info.GetValue(obj, new object[] { key });
                        }
                        else
                        {
                            obj = info.GetValue(obj, null);
                        }
                    }
                }
            }
            return(obj);
        }
Exemple #6
0
 /// <summary>
 /// Format constructor
 /// </summary>
 /// <param name="format"></param>
 public TextSerialiser(TextFormat format, IStringConversionContext context = null)
 {
     Format  = format;
     Context = context;
 }