No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Aplicando el principio de responsabilidad única

6/16
Recursos

Aportes 18

Preguntas 2

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

o inicia sesión.

Dejo mi propuesta de clase ExportHelper (clase que reemplaza a ExportStudents) usando generics de modo que se pueda reutilizar con otros modelos.
Tiene una restriccion y es que solo podria ser usada con modelos que internamente tengan como mucho colecciones de tipos basicos (listas de enteros, listas de dobles, arreglos de enteros, etc).

using System.Collections;
using System.Text;

namespace SingleResponsability
{
    public class ExportHelper<T>
    {
        public void ExportToCSV(IEnumerable<T> items)
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            string header = "";
            string[] dataRows = new string[items.Count()];
            foreach (var prop in typeof(T).GetProperties())
            {
                header += $"{prop.Name};";
                for (int i = 0; i < items.Count(); i++)
                {
                    var propValue = prop.GetValue(items.ToArray()[i]);
                    var propType = propValue.GetType();
                    if(propType.Name != nameof(String) 
                        && propType.GetInterface(nameof(IEnumerable)) != null)
                    {
                        dataRows[i] += $"{String.Join("|", (propValue as IEnumerable).Cast<object>().Select(x => x.ToString()))};";

                    }
                    else
                    {
                        dataRows[i] += $"{propValue};";
                    }
                }
            }
            sb.AppendLine(header.Trim(';'));
            foreach (var dataRow in dataRows)
            {
                sb.AppendLine(dataRow.Trim(';'));
            }
            System.IO.File.WriteAllText(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"Export_{typeof(T).ToString()}.csv"), sb.ToString(), Encoding.Unicode);
        }
    }
}

La implementacion en la clase program seria asi

using SingleResponsability;

StudentRepository studentRepository = new();
ExportHelper<Student> studentExport = new();
studentExport.ExportToCSV(studentRepository.GetAll());
Console.WriteLine("Proceso Completado");

Al crear la clase ExportHelper me aparecía un error CS0101, estuve revisando un rato, pero el error se resolvió cerrando y volviendo a abrir el VSCode.

Espero que les sirva. 😄

Comparto mi propuesta para ExportHelper

Básicamente lo que realice fue que fuera un extended method, y le agregue un constraint para que solo aplique para clases, adicionalmente utilice refelection para recuperar el nombre de las propiedades del genérico y así mismo obtener los valores.

using System.Text;
using System.Collections;
namespace SingleResponsability
{
    public static class ExportHelper
    {

        public static void Export<T>(this IEnumerable<T> source) where T : class
        {
            var sb = new StringBuilder();
            var properties = typeof(T).GetProperties();
            var headers = string.Join(";",properties.Select(p => p.Name));
            sb.AppendLine(headers);
            foreach (var item in source)
            {
                string line = string.Empty;
                foreach (var prop in properties)
                {
                    object? value = prop.GetValue(item, null);

                    if (value is null) continue;
                    
                    if (value is not string && value is IEnumerable valuearray){
                        var values = valuearray.Cast<object>().Select(v => v); 
                        line += string.Join("|",values);
                        continue;
                    }

                    line += $"{value};";
                }
                sb.AppendLine(line);
                System.IO.File.WriteAllText(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Students.csv"), sb.ToString(), Encoding.Unicode);
            }
        }
    }
}

Dejo mi propuesta de clase ExportHelper

using System.Collections;
using System.Text;

namespace SingleResponsability
{
    public class ExportHelper
    {
        public static void ExportCSV<T>(IEnumerable<T> items) where T : class
        {

            StringBuilder sb = new StringBuilder();
            string csvHeader = String.Join(";", typeof(T).GetProperties().Select(x => x.Name.ToString()));
            sb.AppendLine(csvHeader);

            foreach (var item in items)
            {
                string csvData = String.Join(";", typeof(T).GetProperties().Select(x => 
                {
                    object? valueProperty = x.GetValue(item);
                    if (valueProperty is null) return string.Empty;
                    else if (valueProperty is not String && valueProperty is IEnumerable valuesListProperty)
                    {
                        string line = string.Empty;
                        var valores = valuesListProperty.Cast<object>().ToList().Select(x => x);
                        line += string.Join("|", valores);
                        return line;
                    }
                    else return valueProperty;
                }));
                
                sb.AppendLine(csvData);
            }
            System.IO.File.WriteAllText(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{typeof(T).Name}.csv"), sb.ToString(), Encoding.Unicode);

        }
    }
}

using System.Text;

namespace SingleResponsability
{
    public static class ExportHelper
    {
        public static void ExportData<T>(IEnumerable<T> data, string fileName, Func<T, string> dataToString)
        {
            StringBuilder sb = new();
            sb.AppendLine("Id;FullName;Grades");
            foreach (var item in data)
            {
                sb.AppendLine(dataToString(item));
            }
            File.WriteAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName), sb.ToString(), Encoding.Unicode);
        }
    }
}
namespace SingleResponsability
{
    public static class ExportStudent
    {
        public static void Export(IEnumerable<Student> students)
        {
            ExportHelper.ExportData(students, "Students.csv", student => $"{student.Id};{student.FullName};{string.Join("|", student.Grades)}");
        }
    }
}

using SingleResponsability;
StudentRepository _ = new();
ExportStudent.Export(StudentRepository.GetAll());
Console.WriteLine("Proceso Completado");

Puede que algunos al hacerle pull y ver los codigos les aparezca error en todo, esto se resuelve yendose al .csproj y en <TargetFramework> </TargetFramework> ponerle la versiond e netcore que estan usando. Despues de esto hagan dotnet build en la consola y ya esta todo listo

Dejo mi propuesta de clase ExportHelper: ```c# using System.Collections; using System.Text; namespace SingleResponsability { public class ExportHelper<T> { public void ToCsv(IEnumerable<T> data, string name = "Students.csv") { // Create a string builder to store the file content StringBuilder sb = new StringBuilder(); typeof(T).GetProperties().ToList().ForEach(p => sb.Append(p.Name).Append(";")); sb.AppendLine(); // Iterate over the objects in the collection foreach (var item in data) { // Iterate over the properties of the object foreach (var prop in typeof(T).GetProperties()) { // Get the value of the property or an empty string if it's null object value = prop.GetValue(item)??""; // Get the type of the property Type propType = value.GetType(); // If the property is a collection, join the values with a pipe // Otherwise, just append the value if (value is IEnumerable && propType != typeof(string)) sb.Append(string.Join("|", (value as IEnumerable).Cast<object>().Select(x => x?.ToString()))).Append(";"); else sb.Append(value).Append(";"); } // Add a new line sb.AppendLine(); } // Write the file File.WriteAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, name), sb.ToString(), Encoding.Unicode); } } } ```
Clone el repositorio y al tratar de ejecutar el proyecto con dotnet run me da el siguiente error: No se ha podido encontrar un proyecto para ejecutar. Asegúrese de que exista uno en C:\Users\distu\OneDrive\Documentos\Plazit\CursoC#\curso-principios-solid-csharp o pase la ruta de acceso al proyecto mediante --project.
Por si ha alguien le sirve dejaré mi propuesta por aquí: `public static class ExportHelper<T> where T : class` `{` ` public static void ExportCSV(IEnumerable<T> list)` ` {` ` string csv = string.Join(",", list.Select(x => x.ToString()).ToArray());` ` Type typeT = typeof(T);` ` StringBuilder sb = new StringBuilder();` ` sb.AppendLine("Id;Fullname;Grades");` ` foreach (dynamic item in list)` ` {` ` switch (typeT.Name.ToUpper())` ` {` ` case "STUDENT":` ` sb.AppendLine($"{item.Id};{item.Fullname};{string.Join("|", item.Grades)}");` ` break;` ` default:` ` break;` ` }` ` }` ` File.WriteAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Students.csv"), sb.ToString(), Encoding.Unicode);` ` }` `}`
Comparto mi código genérico: using System.Text; namespace SingleResponsability{ public class ExportHelper\<T> { public void ExportStudent(IEnumerable\<T> values) { StringBuilder sb = new StringBuilder(); var headers = string.Join(";", values.GetType().GetProperties().ToList()); sb.AppendLine(headers); foreach (var item in values) { var itemValue = string.Join(";", item); sb.AppendLine(itemValue); } System.IO.File.WriteAllText(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Report.csv"), sb.ToString(), Encoding.Unicode); } }}

Si quieren crear clases e interfaces fácilmente con el namespace correcto usando vscode, pueden descargar la extensión C# Extensions de JosKreativ.

Buen día comunidad. Comparto mi solución. Aprovecho para agradecer a quienes previo a mi aporte hicieron el suyo pues fueron de gran ayuda e iluminación para mi.

 public void ExportCSV(IEnumerable<T> persona)
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            String nameHeader = "";
            var propertiesTypePerson = typeof(T).GetProperties();
            foreach (var personHeader in propertiesTypePerson){
                nameHeader += personHeader.Name + ";";
            }
            nameHeader = nameHeader.Substring(0, nameHeader.Length - 1);
            sb.AppendLine(nameHeader);

            var respCollection = "";
            List<String> values = new List<string>();
            for (int i = 0; i < persona.Count(); i++)
            {
                respCollection = "";
                foreach (var person in propertiesTypePerson)
                {
                    var datos = person.GetValue(persona.ToArray()[i]);
                    var tipo = datos.GetType();
                    
                    if (tipo.FullName.Contains("Collection"))
                    {
                        respCollection = String.Join("|", (datos as IEnumerable).Cast<object>().Select(x => x.ToString()));
                        values.Add(respCollection);
                    }
                    else {
                        values.Add(datos.ToString());
                    }
                }
                sb.AppendLine(String.Join(";",values.ToArray()));
                values.Clear();

            }
            System.IO.File.WriteAllText(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Students.csv"), sb.ToString(), Encoding.Unicode);
        }

Le pedí ayuda a Chat GPT ya que aún soy nuevo en C#:

ExportHelper.cs:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace SingleResponsability
{
    public class ExportHelper<T>
    {
        public void ExportData(IEnumerable<T> data, Func<T, string> toStringFunc)
        {
            string csv = string.Join(",", data.Select(toStringFunc).ToArray());
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("Id;Fullname;Grades");
            foreach (var item in data)
            {
                sb.AppendLine(toStringFunc(item));
            }
            File.WriteAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Data.csv"), sb.ToString(), Encoding.Unicode);
        }
    }
}

Program.cs:

using SingleResponsability;

public class Program
{
    public static void Main()
    {
        StudentRepository studentRepository = new StudentRepository();
        ExportHelper<Student> exportHelper = new ExportHelper<Student>();
        exportHelper.ExportData(studentRepository.GetAll(), x => x.ToString());
        Console.WriteLine("Proceso Completado");
    }
}

Como dato, no es necesario usar

namespace SingleResponsability 
{
	//Codigo 
}

En lugar de eso pueden simplemente

namespace SingleResponsability; 
// Codigo

Esto para que la identacion de su codigo no crezca y sea mas facil de leer 😉

Esta es mi propuesta de la case ExportHelper:

using System.Collections;
using System.Reflection;
using System.Text;

namespace SingleResponsability
{
    public class ExportHelper<T> where T : class 
    {
        public void ExportToCSV(IEnumerable<T> items )
        {
            Type type = typeof(T);
            string classNme =  type.Name;

            string csv = String.Join(",", items.Select(x => x.ToString()).ToArray());
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            //Obten las propiedades de la clase
            PropertyInfo[] properties = type.GetProperties();
            string appentLine = string.Empty;
            foreach (PropertyInfo property in properties)
            {
                appentLine+=$"{property.Name};";
            }
            sb.AppendLine(appentLine);

            foreach (var item in items)
            {
                string valueOfProperty = string.Empty;
                foreach (PropertyInfo property in properties)
                {
                    Type propertyType = property.PropertyType;
                    if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(List<>))
                    {
                        IList list = (IList)property.GetValue(item);
                        if (list != null)
                        {
                            
                            foreach (object listItem in list)
                            {
                                valueOfProperty += $"{(listItem != null ? listItem.ToString() : "null")}|";
                            }
                            valueOfProperty += ";";
                        }
                        else
                        {
                            valueOfProperty += "null";
                        }
                    }
                    else{
                        object value = property.GetValue(item);
                        valueOfProperty += $"{(value != null ? value.ToString() : "null")};";

                    }
                }
                sb.AppendLine(valueOfProperty);
                //sb.AppendLine($"{item.Id};{item.Fullname};{string.Join("|", item.Grades)}");
            }
            System.IO.File.WriteAllText(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{classNme}.csv"), sb.ToString(), Encoding.Unicode);
        }
    }
}

Y la implementación:

using SingleResponsability;

StudentRepository studentRepository = new();
ExportHelper<Student> exportStudent = new ();
exportStudent.ExportToCSV(studentRepository.GetAll());
Console.WriteLine("Proceso Completado");

Siendo un helper convertí la función en estática para no crear una instancia

public static void ExportStudents(IEnumerable<Student> students)
        {
            functionCode
        }

Y así lo invoco en program

StudentRepository studentRepository = new();
ExportHelper.ExportStudents(studentRepository.GetAll());
Console.WriteLine("Proceso Completado");

Podría ser esto una mala práctica??

Mi propuesta:

        public void Export<T>(string header, IEnumerable<T> registers) 
        {

            System.Text.StringBuilder sb = new System.Text.StringBuilder();

            sb.AppendLine(header);
            
            foreach (var item in registers)
            {
                if (item == null) continue;
                Type type = item.GetType();
                PropertyInfo[] props = type.GetProperties();
                string lineaCsv = "";
                foreach (var prop in props)
                {
                    lineaCsv+= prop.GetValue(item) + ";";
                }

                sb.AppendLine(lineaCsv);
            }
            System.IO.File.WriteAllText(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Registers.csv"), sb.ToString(), Encoding.UTF8);
        }