Estrutura / técnicas de dados ideais para armazenar dados genéricos do agendador em C #

8

Eu estou tentando implementar um objeto de agendador genérico em c # 4, que exibirá uma tabela em HTML. O objetivo básico é mostrar algum objeto juntamente com vários atributos e se ele estava fazendo algo em um determinado período de tempo.

O agendador produzirá uma tabela exibindo os cabeçalhos:

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

Desejo inicializar a tabela com uma data de início e uma data de término para criar o período (idealmente também pode ser feito por outros períodos, por exemplo, horas, mas isso não é vital). Desejo, então, fornecer um objeto genérico que terá eventos associados.

Onde um objeto tem eventos dentro do período, quero que uma célula da tabela seja marcada

Por exemplo

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

Então, eu criei o agendador com Data de início = 1/1/2011 e data final 31/1/2011

Gostaria de dar a ele meu objeto pessoal (já classificado) e dizer quais campos eu quero exibir (nome, altura, peso)

Cada pessoa tem eventos com data de início e de término. Alguns eventos começarão e terminarão fora, mas ainda deverão ser mostrados na data relevante etc.

Idealmente, eu gostaria de poder fornecer um objeto de reserva de classe, por exemplo. Então, eu estou tentando mantê-lo genérico.

Eu vi implementações Javasript etc de similares.

O que seria uma boa estrutura de dados para isso? Quaisquer pensamentos sobre técnicas que eu possa usar para torná-lo genérico. Eu não sou ótimo com genéricos, então qualquer dica é apreciada.

GraemeMiller
fonte
com os genéricos, você ainda precisa de uma classe ou interface básica para torná-lo seguro. Você pode usar o Reflection para obter as propriedades em tempo de execução, mas isso é mais lento e é
executado
Sim, eu esperava que a classe base da estrutura de dados tivesse algum tipo de estrutura segurando os cabeçalhos das colunas laterais (que podem ser de 1 ... a n), algum tipo de estrutura segurando os cabeçalhos das colunas principais (que seriam tão grandes quanto o tempo) período) e estruturas que mantêm as linhas reais. A parte genérica era a capacidade de passar algum objeto aleatório e definir o que eu definiria as colunas necessárias para etc.
GraemeMiller 12/12/11
Já pensou em usar a palavra-chave "dinâmica" para esta tarefa?
precisa saber é o seguinte
1
Essa discussão interessante sobre como projetar dados pode fornecer orientação / inspiração.
TheSilverBullet 13/09/12
Se você não precisar executar nenhuma operação real nos dados do campo (altura, peso, etc.), poderá usar a reflexão conforme descrito nesta resposta no Stack Overflow para obter os valores e nomes das propriedades a serem exibidos no objeto.
Nemec #

Respostas:

2

Eu não acho isso muito difícil. o que estou perdendo?

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;
    }
}

Não vejo uma boa maneira de tornar genéricas nossas classes ScheduledPerson, pois parece que os campos podem ser qualquer coisa. Estou armazenando os valores do campo como Objetos, pois não vejo nada que exija que eles sejam dinâmicos. Apenas verifique se todos os tipos de valor de campo têm uma implementação sensata de ToString ().

Se você deseja que os Eventos sejam uma Lista de DateRange ou sua própria classe de Eventos, em vez de Tupla, sinta-se à vontade.

Resta então escrever uma classe separada para renderizar cada ScheduledPerson em uma tabela, além de descobrir todos os cabeçalhos de todos os registros do ScheduledPerson. Se você estiver lidando com dez mil pessoas, desejará uma solução melhor que tenha todos os cabeçalhos armazenados, mas para a maioria dos aplicativos, não será tão ruim enumerar todos os Campos em todas as ScheduledPersons para descobrir os cabeçalhos.

Patrick Szalapski
fonte
0

Em geral, eu não armazenaria os dados da sua solução com base na maneira como você deseja exibi-los. Isso leva a soluções muito específicas que dificultam as coisas quando suas necessidades mudam. Eu detalharia as coisas em termos de entidades em sua solução e, em seguida, criaria um conjunto de consultas LINQ que gerariam seus dados de exibição na hora de gerar o relatório.

Todo o código abaixo é estrutural e omite a inicialização 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;}
}

Agora, na prática, eu os armazenaria em algum tipo de banco de dados e faria todas as consultas em tempo de execução com algo como NHibernate ou Entity Framework. Mas, para fins de demonstração na memória, as consultas para produzir suas linhas de tabela seriam as seguintes:

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);
}    

Em seguida, no renderizador, basta combinar as colunas para saber onde colocar o 'X' para marcar que a data está preenchida. Com mais esforço, você pode refatorar isso para uma solução muito mais elegante, mas esse é o básico.

Steve Mitcham
fonte