Example #1
0
        private readonly PropertyInfo?count; // if null then object supports Slice method with Range parameter

        /// <summary>
        /// Initializes a new slice of collection or array.
        /// </summary>
        /// <param name="collection">The collection or array.</param>
        /// <param name="range">The requested range of collection or array. Should of type <see cref="Range"/>.</param>
        /// <exception cref="ArgumentException"><paramref name="collection"/> doesn't implement <c>Slice</c> method, <c>Length</c> or <c>Count</c> property; or <paramref name="range"/> is not of type <see cref="Range"/>.</exception>
        public SliceExpression(Expression collection, Expression range)
        {
            if (collection is null)
            {
                throw new ArgumentNullException(nameof(collection));
            }
            if (range is null)
            {
                throw new ArgumentNullException(nameof(range));
            }
            if (range.Type != typeof(Range))
            {
                throw new ArgumentException(ExceptionMessages.TypeExpected <Range>(), nameof(range));
            }
            var resolved = false;

            if (collection.Type.IsSZArray)
            {
                slice    = null;
                count    = null;
                resolved = true;
            }
            else if (collection.Type == typeof(string))
            {
                slice    = new Func <string, Range, string>(StringExtensions.Substring).Method;
                count    = null;
                resolved = true;
            }
            else
            {
                foreach (var slice in GetSliceMethods(collection.Type))
                {
                    var parameters = slice.GetParameters();
                    if (parameters.LongLength == 1L && parameters[0].ParameterType == typeof(Range))
                    {
                        count      = null;
                        this.slice = slice;
                        resolved   = true;
                        break;
                    }

                    var intType = typeof(int);
                    if (parameters.LongLength == 2L && parameters[0].ParameterType == intType && parameters[1].ParameterType == intType)
                    {
                        count      = CollectionAccessExpression.GetCountProperty(collection.Type) ?? throw new ArgumentException(ExceptionMessages.CollectionExpected(collection.Type), nameof(collection));
                        this.slice = slice;
                        resolved   = true;
                        break;
                    }
                }
            }

            Range      = resolved ? range : throw new ArgumentException(ExceptionMessages.CollectionExpected(collection.Type), nameof(collection));
            Collection = collection;
        }
        private readonly PropertyInfo?count;    // if null then indexer != null because it has explicit Index parameter type

        /// <summary>
        /// Initializes a new collection access expression.
        /// </summary>
        /// <param name="collection">The expression representing collection.</param>
        /// <param name="index">The index of the element. Should be of type <see cref="System.Index"/>.</param>
        /// <exception cref="ArgumentException"><paramref name="collection"/> doesn't provide implicit support of Index expression.</exception>
        /// <seealso href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/ranges">Ranges and Indicies</seealso>
        public CollectionAccessExpression(Expression collection, Expression index)
        {
            if (collection is null)
            {
                throw new ArgumentNullException(nameof(collection));
            }
            if (index is null)
            {
                throw new ArgumentNullException(nameof(index));
            }
            if (index.Type != typeof(Index))
            {
                throw new ArgumentException(ExceptionMessages.TypeExpected <Index>(), nameof(index));
            }
            var resolved = false;

            if (collection.Type.IsSZArray)
            {
                indexer  = count = null;
                resolved = true;
            }
            else
            {
                foreach (var indexer in GetIndexers(collection.Type))
                {
                    var parameters = indexer.GetIndexParameters();
                    if (parameters.LongLength != 1L)
                    {
                        continue;
                    }
                    var firstParam = parameters[0].ParameterType;
                    if (firstParam == typeof(Index))
                    {
                        count        = null;
                        this.indexer = indexer;
                        resolved     = true;
                        break;
                    }

                    if (firstParam == typeof(int))
                    {
                        count        = GetCountProperty(collection.Type) ?? throw new ArgumentException(ExceptionMessages.CollectionExpected(collection.Type), nameof(collection));
                        this.indexer = indexer;
                        resolved     = true;
                        break;
                    }
                }
            }

            Index      = resolved ? index : throw new ArgumentException(ExceptionMessages.CollectionExpected(collection.Type), nameof(collection));
            Collection = collection;
        }