0

I am wondering if something like this is possible. I am looking to create a method that can be called instead of List.Add. The method would check any/all string properties and make sure they don't exceed their specific given max lengths, and if so truncate to proper size. I would ideally like it to be generic so that it will not only work for ObjectA, but also ObjectB, ObjectC, etc.

I am open to any and all suggestions. I know it seems like a weird thing to do, but I have a lot of different objects I am working with and potentially millions of those object instances in totality across all my lists. I mainly just need a way to ensure that any objects with properties exceeding their max string limit are truncated and logged via the Worker class in a timely way. Thanks!

public class ObjectA {
   public Guid aID {get; set;}
   [MaxLength(128)]
   public string aName {get; set;}
   [MaxLegnth(30)]
   public string aType {get; set;}
}

--

public class Worker {
    private void Work() {
        List<ObjectA> listOfA = new List<ObjectA>();

        listOfA.CustomAddMethod(new ObjectA(new Guid, "Something", "Unknown"));
    }

    // ??????
    private CustomAddMethod(T object) {
        foreach property {
           if (isStringProperty && isGreaterThanMaxLength) {
                // truncate to proper size
                // log for truncation message
           }
           // Then add to list
        }
    }
}
Jeremy P
  • 1,309
  • 2
  • 13
  • 22
  • What type is the list in "Then add to list"? – canton7 Jun 07 '21 at 16:27
  • Yes, this is possible. By defining a class that inherits from List or create an extension medthod (not so good pattern, limited). The cleanest way is to create a wrapper embedding by composition an internal private or protected List and you need to expose any properties and methods you want, thus you will be able to control anything as you want. [Prefer composition over inheritance?](https://stackoverflow.com/questions/49002/prefer-composition-over-inheritance) | [Composition vs. Inheritance: How to Choose?](https://www.thoughtworks.com/insights/blog/composition-vs-inheritance-how-choose) –  Jun 07 '21 at 16:30
  • @canton7 List, list of whatever object is passed in – Jeremy P Jun 07 '21 at 16:30
  • @JeremyP So that list will disappear as soon as the `CustomAddMethod` returns? – canton7 Jun 07 '21 at 16:30
  • You can also create an extension method – Jonathan Alfaro Jun 07 '21 at 16:31
  • Is this only for logging purposes? Perhaps you can elaborate a bit on the problem you're trying to solve rather than the solution you're attempting? Because modifying an object as part of inserting it into a list is not very intuitive from the perspective of the method caller. – Xerillio Jun 07 '21 at 16:34

1 Answers1

1

You can create an extension method.

Here is a code snip. You can improve the performance by implementing a cache, for example, using a dictionary to store the properties and the MaxLengthAttribute based on object's type.

public static class ListExtensions
{
    public static void CustomAdd<T>(this List<T> list, T item, Action<string> logger = null)
    {
        var propertyInfos = typeof(T)
            .GetProperties(BindingFlags.Instance | BindingFlags.Public)
            .Where(propertyInfo => propertyInfo.PropertyType == typeof(string))
            .ToList();

        foreach (var propInfo in propertyInfos)
        {
            var maxLengthAttr = propInfo
                .GetCustomAttributes(typeof(MaxLengthAttribute))
                .Cast<MaxLengthAttribute>()
                .FirstOrDefault();

            if (maxLengthAttr is null)
                continue;

            var currentString = (string)propInfo.GetValue(item);
            if (!maxLengthAttr.IsValid(currentString))
            {
                var newValue = currentString.Substring(0, maxLengthAttr.Length);
                logger?.Invoke(
                    $"Resolving error: {maxLengthAttr.FormatErrorMessage(propInfo.Name)}\n" +
                    $"Old Value: {currentString}\n" +
                    $"New Value: {newValue}"
                );

                propInfo.SetValue(item, newValue);
            }
        }

        list.Add(item);
    }
}

Example of usage (code removed for brevity):

public class Person
{
    [MaxLength(4)]
    public string Name { get; set; }
}


...
var personList = new List<Person>();
personList.CustomAdd(
    new Person {Name = "John Doe"},
    message => Debug.WriteLine(message)
);
...

As result the Jhon Doe string will be trimmed to Jhon

denys-vega
  • 3,522
  • 1
  • 19
  • 24