Generare e di compilare il nome di indice di traduzione e/o la mappatura per velocizzare la riutilizzabilità

StackOverflow https://stackoverflow.com//questions/11665503

  •  11-12-2019
  •  | 
  •  

Domanda

Supponiamo di ottenere i dati da un servizio (che non riesco a controllare) come:

public class Data
{
    // an array of column names
    public string[] ColumnNames { get; set; }

    // an array of rows that contain arrays of strings as column values
    public string[][] Rows { get; get; }
}

e nel livello intermedio vorrei mappa/tradurre questo per un IEnumerable<Entity> dove i nomi delle colonne Data può essere rappresentato come nella mia proprietà Entity classe.Ho detto può perché io non bisogno di tutti i dati restituiti dal servizio, ma solo una parte.

Trasformazione

Questa è un'astrazione di un algoritmo che vorresti fare la traduzione:

  1. creare un IDictionary<string, int> di ColumnNames quindi posso facilmente sulla mappa i nomi delle singole colonne di indici di un array in singole righe.
  2. utilizzare la reflection per il mio esame di Entity proprietà' nomi quindi sono in grado di abbinare con i nomi di colonna
  3. scorrere Data.Rows e creare il mio Entity oggetti e popolare proprietà secondo la mappatura fatta in #1.Probabile utilizzo di riflessione e di SetValue sulla proprietà per impostare loro.

Ottimizzazione

Superiore algoritmo del lavoro di corso, ma penso che a causa di esso utilizza la riflessione si dovrebbe fare un po 'di cache e forse un po' al volo compilation, che potrebbe accelerare le cose notevolmente.

Quando i passaggi 1 e 2 sono fatto, si potrebbe effettivamente generare un metodo che accetta un array di stringhe e crea il mio entità utilizzando indici direttamente e compilarlo e cache per poterlo riutilizzare in futuro.

Io sono di solito una pagina di risultati, quindi, le successive richieste di riutilizzare la stessa compilato metodo.

Ulteriori effetti

Questo non è un imperativo per la domanda (e risposta), ma ho anche creato due attributi che aiutano con la colonna di mapping di proprietà quando questi non corrispondono a nomi.Ho creato la più ovvia MapNameAttribute (che prende una stringa e, facoltativamente, anche abilitare il caso di sensibilità) e IgnoreMappingAttribute per le proprietà sul mio Entity che non dovrebbe mappa di tutti i dati.Ma questi attributi sono leggere nel passaggio 2 della superiore algoritmo così i nomi di proprietà sono raccolti e rinominato secondo questo dichiarativa di metadati in modo che corrispondano i nomi di colonna.

Domanda

Qual è il modo migliore e più semplice per generare e compilare tale metodo?Le espressioni Lambda? CSharpCodeProvider classe?

Non è forse un esempio di generazione di e ha compilato il codice che fa una cosa simile?Credo che le mappature sono piuttosto scenario comune.

Nota:Nel frattempo ho deciso PetaPoco (e forse anche di massa) perché, per quanto ne so fanno entrambi la compilazione e la memorizzazione nella cache di volare esattamente per la mappatura scopi.

È stato utile?

Soluzione

Suggerimento: ottenere FastMember da NuGet

Poi basta usare:

var accessor = TypeAccessor.Create(typeof(Entity));

Quindi solo nel ciclo, quando hai trovato l' memberName e newValue per l'iterazione corrente:

accessor[obj, memberName] = newValue;

Questo è stato progettato per fare quello che stai chiedendo;internamente, mantiene un insieme di tipi se ha mai visto prima.Quando un nuovo tipo di visto, crea una nuova sottoclasse di TypeAccessor on-the-fly (via TypeBuilder) e lo memorizza nella cache.Unica ogni TypeAccessor è a conoscenza delle proprietà di quel tipo, e fondamentalmente solo agisce come un:

switch(memberName) {
    case "Foo": obj.Foo = (int)newValue;
    case "Bar": obj.Bar = (string)newValue;
    // etc
}

Perché questo è nella cache, è solo pagare alcun costo (e non è un grande il costo) la prima volta che si vede mai il vostro tipo;il resto del tempo, è libero.Perché utilizza ILGenerator direttamente, inoltre, evita inutili astrazione, per esempio via Expression o CodeDom, quindi è circa veloce come si può.

(Devo anche precisare che per la dynamic tipi, vale a diretipi che implementano IDynamicMetaObjectProvider, è possibile utilizzare una singola istanza di supporto ogni oggetto).


Aggiuntive:

Che cosa è potrebbe fare è:prendere l'esistente FastMember codice e modificarlo a processo MapNameAttribute e IgnoreMappingAttribute durante WriteGetter e WriteSetter;quindi tutti i voodoo accade sul vostro dati nomi, piuttosto che il membro nomi.

Questo significherebbe cambiare le linee:

il.Emit(OpCodes.Ldstr, prop.Name);

e

il.Emit(OpCodes.Ldstr, field.Name);

in entrambi i WriteGetter e WriteSetter, e facendo un continue all'inizio del foreach loop se dovrebbe essere ignorato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top