Reflection optimization for export CSV on large scale So, I'm building export/import CSV helper. I have some performance issues in the code below. it takes me to parse CSV of 25,000 rows at 7 seconds.
If someone can help, it will be awesome!            

public System.IO.Stream ParseContent&lt;T&gt;(IEnumerable&lt;T&gt; entities) where T : class
    {
        if (entities == null)
            throw new ArgumentException(nameof(entities), "List accepted is empty.");

        Type type = entities.First().GetType();

        PropertyInfo[] properties = type.GetProperties();

        string headers = GenerateTemplate(properties);

        //No headers accepted - cannot export the content
        if (string.IsNullOrEmpty(headers))
            return null;

        string contentToExport = $"{headers}{NewLineDelimiter}";

        foreach (T entity in entities)
        {
            if (entity == null)
                continue;

            string template = this.ExportLine(entity, properties);

            contentToExport += $"{template}{NewLineDelimiter}";
        }

        byte[] bytes = System.Text.Encoding.UTF8.GetBytes(contentToExport);
        System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(bytes);

        return memoryStream;
    }

    private string ExportLine&lt;T&gt;(T entity, PropertyInfo[] properties) where T : class
    {
        if (entity == null || properties == null)
            return string.Empty;

        string template = "";

        foreach (PropertyInfo property in properties)
        {
            string value = null;

            if (property.PropertyType.IsGenericType &amp;&amp; property.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable&lt;&gt;))
            {
                Type underlyingType = property.PropertyType.GetGenericArguments()[0];

                if (underlyingType.IsValueType || underlyingType == typeof(string))
                {
                    System.Collections.IEnumerable list = (System.Collections.IEnumerable)property.GetValue(entity);

                    value = string.Join(EnumerableValueDelimiter, list.Cast&lt;string&gt;());
                }
            }
            else if (property.PropertyType.IsClass &amp;&amp; (!property.PropertyType.IsPrimitive &amp;&amp; !property.PropertyType.IsEnum) &amp;&amp; property.PropertyType != typeof(string))
            {
                //Object type. need to be serialized
                object propertyValue = property.GetValue(entity);

                if (propertyValue != null)
                    value = JsonConvert.SerializeObject(propertyValue);
                else
                    value = "null";
            }
            else
            {
                value = property.GetValue(entity)?.ToString();
            }

            if (string.IsNullOrEmpty(value))
                value = "";

            template += $"{value}{LineValuesDelimiter}";
        }

        //Removing the last delimiter at the row.
        if (template.Length &gt; 0)
            template = template.Remove(template.Length - 1, 1);

        return template;
    }
ParseContent()  


Type type = entities.First().GetType(); can throw an exception if entities doesn't contain any items. I may be wrong but you could use the T as well like  Type type = typeof(T);.
If entities is null an ArgumentNullException should be thrown instead of an ArgumentException.  
The foreach could be simplified and you should use a StringBuilder instead of concating strings in a loop. Thats because strings are immutable and for each contentToExport += $"{template}{NewLineDelimiter}"; you create a new string object.  
If the right hand side of an assignment makes the type clear one should use var instead of the concrete type.  
Omitting braces {} althought they might be optional can lead to hidden and therefor hard to find bugs. I would like to encourage you to always use them.  
Having a variable memoryStream doesn't buy you anything. Just return the new memorystream.  


Applying these points will lead to  

public System.IO.Stream ParseContent&lt;T&gt;(IEnumerable&lt;T&gt; entities) where T : class
{
    if (entities == null)
    {
        throw new ArgumentNullException(nameof(entities), "List accepted is empty.");
    }
    if (!entities.Any())
    {
        //assuming thats the desired behaviour
        return null;
    }

    Type type = typeof(T);

    PropertyInfo[] properties = type.GetProperties();

    string headers = GenerateTemplate(properties);

    //No headers accepted - cannot export the content
    if (string.IsNullOrEmpty(headers))
    {
        return null;
    }

    StringBuilder contentToExport = new StringBuilder( $"{headers}{NewLineDelimiter}");

    foreach (T entity in entities.Where(e=&gt;e!=null))
    {

        string template = this.ExportLine(entity, properties);
        contentToExport.Append($"{template}{NewLineDelimiter}");
    }

    byte[] bytes = System.Text.Encoding.UTF8.GetBytes(contentToExport.ToString());

    return new System.IO.MemoryStream(bytes);
}