Beispiel #1
0
        private void GetTokens(List <Token <ModelTokenType> > tokens, ICycleDetector detector, object value)
        {
            if (value == null)
            {
                tokens.Add(ModelGrammar.TokenNull);
                return;
            }

            // test for cycles
            if (detector.Add(value))
            {
                switch (this.Settings.GraphCycles)
                {
                case GraphCycleType.Reference:
                {
                    // no need to remove value as was duplicate reference
                    throw new GraphCycleException(GraphCycleType.Reference, "Graph cycle detected: repeated references");
                }

                case GraphCycleType.MaxDepth:
                {
                    throw new GraphCycleException(GraphCycleType.MaxDepth, "Graph cycle potentially detected: maximum depth exceeded");
                }

                default:
                case GraphCycleType.Ignore:
                {
                    // no need to remove value as was duplicate reference
                    // replace cycle with null
                    tokens.Add(ModelGrammar.TokenNull);
                    return;
                }
                }
            }

            try
            {
                foreach (var filter in this.Filters)
                {
                    IEnumerable <Token <ModelTokenType> > filterResult;
                    if (filter.TryWrite(this.Settings, value, out filterResult))
                    {
                        // found a successful match
                        tokens.AddRange(filterResult);
                        return;
                    }
                }

                Type type = value.GetType();

                // must test enumerations before other value types
                if (type.IsEnum)
                {
                    tokens.Add(ModelGrammar.TokenPrimitive((Enum)value));
                    return;
                }

                // Type.GetTypeCode() allows us to more efficiently switch type
                switch (Type.GetTypeCode(type))
                {
                case TypeCode.Boolean:
                {
                    tokens.Add(true.Equals(value) ? ModelGrammar.TokenTrue : ModelGrammar.TokenFalse);
                    return;
                }

                case TypeCode.Byte:
                case TypeCode.Decimal:
                case TypeCode.Int16:
                case TypeCode.Int32:
                case TypeCode.Int64:
                case TypeCode.SByte:
                case TypeCode.UInt16:
                case TypeCode.UInt32:
                case TypeCode.UInt64:
                {
                    tokens.Add(ModelGrammar.TokenPrimitive((ValueType)value));
                    return;
                }

                case TypeCode.Double:
                {
                    double doubleVal = (double)value;

                    if (Double.IsNaN(doubleVal))
                    {
                        tokens.Add(ModelGrammar.TokenNaN);
                    }
                    else if (Double.IsPositiveInfinity(doubleVal))
                    {
                        tokens.Add(ModelGrammar.TokenPositiveInfinity);
                    }
                    else if (Double.IsNegativeInfinity(doubleVal))
                    {
                        tokens.Add(ModelGrammar.TokenNegativeInfinity);
                    }
                    else
                    {
                        tokens.Add(ModelGrammar.TokenPrimitive(doubleVal));
                    }
                    return;
                }

                case TypeCode.Single:
                {
                    float floatVal = (float)value;

                    if (Single.IsNaN(floatVal))
                    {
                        // use the Double equivalent
                        tokens.Add(ModelGrammar.TokenNaN);
                    }
                    else if (Single.IsPositiveInfinity(floatVal))
                    {
                        // use the Double equivalent
                        tokens.Add(ModelGrammar.TokenPositiveInfinity);
                    }
                    else if (Single.IsNegativeInfinity(floatVal))
                    {
                        // use the Double equivalent
                        tokens.Add(ModelGrammar.TokenNegativeInfinity);
                    }
                    else
                    {
                        tokens.Add(ModelGrammar.TokenPrimitive(floatVal));
                    }
                    return;
                }

                case TypeCode.Char:
                case TypeCode.DateTime:
                case TypeCode.String:
                {
                    tokens.Add(ModelGrammar.TokenPrimitive(value));
                    return;
                }

                case TypeCode.DBNull:
                case TypeCode.Empty:
                {
                    tokens.Add(ModelGrammar.TokenNull);
                    return;
                }
                }

                if (value is IEnumerable)
                {
                    this.GetArrayTokens(tokens, detector, (IEnumerable)value);
                    return;
                }

                if (value is Guid || value is Uri || value is Version)
                {
                    tokens.Add(ModelGrammar.TokenPrimitive(value));
                    return;
                }

                if (value is TimeSpan)
                {
                    tokens.Add(ModelGrammar.TokenPrimitive((TimeSpan)value));
                    return;
                }

#if NET40 && !WINDOWS_PHONE
                if (value is System.Dynamic.DynamicObject)
                {
                    // TODO: expand to all IDynamicMetaObjectProvider?
                    this.GetObjectTokens(tokens, detector, type, (System.Dynamic.DynamicObject)value);
                    return;
                }
#endif

                // all other structs and classes
                this.GetObjectTokens(tokens, detector, type, value);
            }
            finally
            {
                detector.Remove(value);
            }
        }