Sto provando a creare un semplice strumento di reporting, in cui un utente può selezionare da un insieme di KPI, grafici, funzioni di aggregazione e altri parametri, fare clic su un pulsante, dopo di che un servizio wcf viene chiamato, che restituisce un modello personalizzato con tutti i dati. Questo potrebbe quindi essere visualizzato in un'applicazione MVC/WPF (potrebbe essere entrambi).Interfacce generiche per report semi-ad hoc
Poiché gli utenti potrebbero provenire da diversi paesi, desidero utilizzare le annotazioni di dati per ritrarre tutti i numeri e le intestazioni in un modo adatto alla lingua e ai formati numerici a cui è abituato l'utente corrente.
Il caricamento dei dati e tutto il resto funziona perfettamente, nessun problema. Inoltre, io uso le annotazioni dei dati, quindi tutte le impostazioni specifiche per lingua e cultura sono prese in considerazione. I problemi iniziano quando provo a inserire tutti i dati nel modello che voglio mostrare all'utente.
Quello che sto cercando di fare è avere una classe Report, che contenga una collezione di colonne. Ogni colonna potrebbe essere un elenco di valori int/double/.... Ora, dato che ho a che fare con WCF e la spiegazione di cui sopra implica (per quanto ho capito) l'uso dei generici, presumo di poter usare il [KnownType] o [ServiceKnownType] per le operazioni classes/wcf, mentre effettivamente uso un tipo di base o interfaccia come valore di ritorno. Non ho mai provato questo, ma ho trovato alcune buone spiegazioni che mi sembrano abbastanza logiche, quindi presumo che non avrò grandi problemi per questa parte (almeno spero di no).
In questo momento, i miei interfacce sono in quanto tali (semplificato per concentrarsi sul problema reale che ho):
public interface IReport<T> where T: IConvertible { ICollection<IColumn<T>> Columns { get; set; } }
public interface IColumn<T> where T: IConvertible { ICollection<IValue<T>> Values { get; set; } }
public interface IValue<T> where T: IConvertible { T Value { get; set; } }
Poiché il valore in ogni colonna potrebbe essere un int/doppia/..., presumo devo avere una classe reale solo per il valore (non credo che posso utilizzare un attributo di dati di annotazione su un tipo di raccolta), in quanto tale:
public class IntValue: IValue<int>
{
[DisplayFormat(DataFormatString = "{0:#,##0;-#,##0;'---'}", ApplyFormatInEditMode = true)]
public int Value { get; set; }
}
Naturalmente, che sembra strano, dal momento che si può solo rendilo un valore generico di classe che implementa IValue e sii fatto con esso, ma se faccio la cosa sciocca e fai una lezione per ogni tipo possibile (ora che la digito, suona davvero male, lo so), posso usare l'attributo DisplayFormat e non devo preoccuparmi del modo in cui si presenterà all'utente, ' Sarò sempre appropriato.
Ora, per le classi che implementano iColumn e IReport, che è semplice:
public class Report<T>: IReport<T> where T: IConvertible
{
public ICollection<IColumn<T>> Columns { get; set; }
public Report() { Columns=new List<IColumn<T>>(); }
}
public class Column<T>: IColumn<T> where T: IConvertible
{
public ICollection<IValue<T>> Values { get; set; }
public Column() { Values = new List<IValue<T>>(); }
}
Dall'elenco di interfacce e classi, vi renderete subito conto che questo rende impossibile avere un rapporto in cui alcune colonne avere altri tipi Quindi non è possibile creare un report in cui alcune colonne sono int, alcune sono doppie, ... Poiché il vincolo generico in IReport ti fa specificare un tipo, sei bloccato con quello per tutte le colonne, poiché si propaga al valore di ogni colonna ... E questo è esattamente ciò che voglio davvero.
Mi sento come se non dovessi arrivare da nessuna parte, e probabilmente mi manca qualcosa di veramente semplice, quindi una spinta nella giusta direzione sarebbe apprezzata.
TL; DR: Come si ottiene una raccolta generica in un tipo non generico?
Non riesci a creare il tuo rapporto come 'nuovo IReport'? –
Baldrick
Per quanto posso ora vedere, questo non mi consente di aggiungere una colonna int o doppia, poiché si aspetta che siano IConvertibili, e non QUALSIASI classe di implementazione IConvertible. –