Estructura / técnicas de datos ideales para almacenar datos de planificador genéricos en C #

8

Estoy tratando de implementar un objeto de planificador genérico en C # 4 que generará una tabla en HTML. El objetivo básico es mostrar algún objeto junto con varios atributos, y si estaba haciendo algo en un período de tiempo determinado.

El planificador generará una tabla que muestra los encabezados:

Detail Field 1 ....N| Date1.........N

Quiero inicializar la tabla con una fecha de inicio y una fecha de finalización para crear el rango de fechas (idealmente también podría hacer otros períodos de tiempo, por ejemplo, horas, pero eso no es vital). Luego quiero proporcionar un objeto genérico que tendrá eventos asociados.

Cuando un objeto tiene eventos dentro del período, quiero que se marque una celda de tabla

P.ej

Name Height Weight 1/1/2011 2/1/2011 3/1/20011...... 31/1/2011
Ben  5.11    75       X        X                       X
Bill 5.7     83                X        X

Así que creé el planificador con Fecha de inicio = 1/1/2011 y fecha de finalización 31/1/2011

Me gustaría darle mi objeto persona (ya ordenado) y decirle qué campos quiero mostrar (Nombre, Altura, Peso)

Cada persona tiene eventos que tienen una fecha de inicio y una fecha de finalización. Algunos eventos comenzarán y terminarán de forma inmediata, pero aún deben mostrarse en la fecha relevante, etc.

Idealmente, me gustaría haber podido proporcionarle, por ejemplo, un objeto de reserva de clase también. Así que estoy tratando de mantenerlo genérico.

He visto implementaciones de Javasript, etc. de similares.

¿Cuál sería una buena estructura de datos para esto? Cualquier idea sobre las técnicas que podría usar para hacerlo genérico. No soy bueno con los genéricos, por lo que agradezco cualquier consejo.

GraemeMiller
fuente
con los genéricos aún necesita una clase base o interfaz para que sea segura. Puede usar Reflection para obtener las Propiedades en tiempo de ejecución, pero esto es más lento y solo se
ejecuta
Sí, esperaba que la clase base de la estructura de datos tuviera algún tipo de estructura que contenga encabezados de columna laterales (que puede ser 1 ... a n), algún tipo de estructura que contenga encabezados de columnas principales (que sería tan grande como el momento período), y luego estructuras que contienen las filas reales. La parte genérica era la capacidad de pasar algún objeto al azar y definir que yo entonces definir las columnas I requerida para etc.
GraemeMiller
¿Alguna vez pensó en usar la palabra clave "dinámica" para esta tarea?
Dimi Takis
1
Esta interesante discusión sobre el diseño en torno a los datos podría darle dirección / inspiración.
TheSilverBullet
Si no necesita realizar ninguna operación real en los datos del campo (altura, peso, etc.), puede usar la reflexión como se describe en esta respuesta en Desbordamiento de pila para obtener los valores de propiedad y nombres para mostrar desde el objeto.
nemec

Respuestas:

2

No creo que esto sea demasiado difícil. ¿Qué me estoy perdiendo?

using System;
using System.Collections.Generic;

public class ScheduledPerson {
    public string Name {get; set;}

    public Dictionary<string, Object> Fields {
        get { return _fields; }
        set { _fields = value; }
    }
    private Dictionary<string, Object> _fields = new Dictionary<string, Object>();

    public List<Tuple<DateTime, DateTime>> Events {
        get { return _events; }
        set { _events = value; }
    }
    private List<Tuple<DateTime, DateTime>> _events = new List<Tuple<DateTime, DateTime>>();

    public ScheduledPerson(string name){
        Name = name;
    }
}

No veo una buena manera de hacer que nuestras clases ScheduledPerson sean genéricas, ya que parece que los campos pueden ser cualquier cosa. Estoy almacenando los valores de campo como Objetos, ya que no veo nada que requiera que sean dinámicos. Solo asegúrese de que todos los tipos de valores de campo tengan una implementación ToString () sensible.

Si desea que los eventos sean una lista de DateRange o de su propia clase de eventos en lugar de Tuple, siéntase libre.

Luego le queda a usted escribir una clase separada para representar cada ScheduledPerson en una tabla, junto con averiguar todos los encabezados de todos los registros de ScheduledPerson. Si está tratando con diez mil personas, querrá una mejor solución que tenga todos los encabezados almacenados, pero para la mayoría de las aplicaciones, no será tan malo enumerar todos los campos en todas las personas programadas para descubrir los encabezados.

Patrick Szalapski
fuente
0

En general, no almacenaría los datos para su solución en función de la forma en que desea mostrarlos. Eso lleva a soluciones muy específicas que dificultarán las cosas cuando cambien sus necesidades. Desglosaría las cosas en términos de entidades en su solución y luego crearía un conjunto de consultas LINQ que generarían sus datos de visualización cuando sea el momento de generar el informe.

Todo el código a continuación es estructural y omite la inicialización, etc.

public class Person
{
   public string Name {get;set;}
   public double Height {get;set;}
   public double Weight {get;set;}
}

public class ScheduledEvent
{
   public Person Attendee {get;set;}
   public DateTime EventDate {get;set;}
}

public class Schedule
{
   public DateTime StartDate {get;set; }
   public DateTIme EndDate {get;set;}
   List<Person> Persons {get;set;}
   List<ScheduledEvent> SheduledEvents {get;set;}
}

Ahora, en la práctica, los almacenaría en una base de datos de algún tipo y haría todas las consultas en tiempo de ejecución con algo como NHibernate o Entity Framework. Pero para propósitos de demostración en memoria, las consultas para producir sus líneas de tabla serían las siguientes:

class TableRow
{
   string Name { get;set; }
   string Height {get;set; }
   string Weight {get;set; }
   List<string> DatesWithEvents {get; }
}

var columns = List<string>{ "Name", "Height", "Weight", }.Concat(
                schedule.ScheduledEvents
                  .Select(e=> e.EventDate.ToShortDate())
                  .Distinct())
              .ToList();
var rows = new List<TableRow>();

foreach(var p in schedule.Persons) 
{
   var row = new TableRow();
   row.Name = p.Name;
   row.Height = p.Height;
   row.Weight = p.Weight;
   row.DatesWithEvents = schedule.ScheduledEvents
     .Where(e => e.Person == p)
     .Select(e => e.EventDate.ToShortDate()).Distinct().ToList();
   rows.Add(row);
}    

Luego, en su renderizador, solo combine las columnas para saber dónde pegar la 'X' para marcar que la fecha está llena. Con más esfuerzo, puede refactorizar esto en una solución mucho más elegante, pero esto es lo básico.

Steve Mitcham
fuente