How can you drop items in a ICollection without knowing its TSource? I thought LINQ would be the best route for this, but I cannot figure out how it might be done with Reflection or any other method.
I am trying to implement this in a class that inherits System.Attribute so generic types are not permitted. And, the returned type information must be the same as the type information received on the value parameter of MutateValue. So obviously, generic would be a joy in this case, but is there another solution.
using System;
using System.Collections;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace Dado.ComponentModel.DataMutations
{
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
    public class ApplyMaxLengthStackAttribute : MutationAttribute
    {
        private int _maxLength = -1;
        public object Mutate(object value, int maxLength, IMutationContext context = null)
        {
            _maxLength = maxLength;
            return Mutate(value, context);
        }
        protected override object MutateValue(object value, IMutationContext context)
        {
            if (value != null) {
                if (
                    value is string valueAsString &&
                    (
                        _maxLength > -1 || TryGetStringLengthAttributeValue(context, out _maxLength)
                    ) &&
                    valueAsString.Length > _maxLength
                ) {
                    value = valueAsString.Substring(0, _maxLength);
                }
                else if (
                    value is ICollection valueAsCollection &&
                    (
                        _maxLength > -1 || TryGetMaxLengthAttributeValue(context, out _maxLength)
                    ) &&
                    valueAsCollection.Count > _maxLength
                ) {
                    // Error CS1061
                    value = valueAsCollection.Take(_maxLength);
                }
            }
            _maxLength = -1;
            return value;
        }
        private bool TryGetStringLengthAttributeValue(IMutationContext context, out int maxLength)
        {
            var attribute = context?.Attributes.OfType<StringLengthAttribute>().FirstOrDefault();
            if (attribute != null) {
                maxLength = attribute.MaximumLength;
                return true;
            }
            return TryGetMaxLengthAttributeValue(context, out maxLength);
        }
        private bool TryGetMaxLengthAttributeValue(IMutationContext context, out int maxLength)
        {
            var attribute = context?.Attributes.OfType<MaxLengthAttribute>().FirstOrDefault();
            if (attribute != null) {
                maxLength = attribute.Length;
                return true;
            }
            maxLength = -1;
            return false;
        }
    }
}
You will see this code will not compile and throws this error:
Error CS1061: 'ICollection' does not contain a definition for 'Take' and no extension method 'Take' accepting a first argument of type 'ICollection' could be found (are you missing a using directive or an assembly reference?)
This class is an extension to the Dado.ComponentModel.Mutations project. Definitions for other Dado.ComponentModel.Mutations member definitions should be sought there.