2010-02-04 33 views
10

Quiero cargar un archivo de propiedades (es un archivo .csv que tiene en cada línea un nombre y un valor numérico asociado) y luego acceder a los valores de las propiedades de esta manera: FileLoader.PropertyOne o . El problema es que no quiero tener que escribir una propiedad para cada valor, quiero que se generen a partir del archivo. EntoncesGenerar propiedades mediante programación

public class FileLoader 
{ 
    public int Property1 { get; private set; } 
} 

no es lo que estoy buscando. es posible? No veo ninguna forma de hacerlo porque obviamente el compilador no sabría los nombres de las propiedades. Tal vez algo similar?

+1

Escriba una plantilla T4 que genere un archivo .cs dado el .csv. –

+0

posible duplicado de [¿Cómo creo propiedades dinámicas en C#?] (Http://stackoverflow.com/questions/947241/how-do-i-create-dynamic-properties-in-c) – nawfal

Respuesta

13

En C# 4.0, se puede utilizar el ExpandoObject, enlace contiene buena explicación y un par de casos de uso, como:

dynamic contact = new ExpandoObject(); 
contact.Name = "Patrick Hines"; 
contact.Phone = "206-555-0144"; 
contact.Address = new ExpandoObject(); 
contact.Address.Street = "123 Main St"; 
contact.Address.City = "Mercer Island"; 
contact.Address.State = "WA"; 
contact.Address.Postal = "68402"; 

A pesar de lo impresionante de la ExpandoObject es dynamicly crear objetos jerárquicos complejos , Supongo que podrías usarlo en general porque es un sintaxis brillante incluso para objetos simples definidos dinámicamente.

EDIT: Aquí es otra respuesta en la adición de SO detalles acerca de los beneficios de ExpandoObject por el mismo redactor que escribió el artículo previamente vinculado

What are the true benefits of ExpandoObject?

+4

En mi opinión, este es uno de los casos que ilustra por qué la dinámica es una mala idea. Sin Intellisense, sin seguridad de tipo, sin comprobaciones en tiempo de compilación, excepciones de tiempo de ejecución: creo que la generación de código sería mucho mejor. – OregonGhost

+0

Incluso antes de ExpandoObject, se podían obtener resultados similares con un objeto 'Dictionary' en vb6, aunque' Dictionary' solo podía contener cosas del tipo 'Object':' MyDict! Address! Street = MyStreetObject'. Uno podría lograr algo similar en vb.net, aunque uno debería tener una propiedad con nombre del último objeto [p. 'st' for' string']: 'MyDict! Address! City.st =" Isla Mercer "'; Tal enfoque probablemente tenía los mismos pros y contras que ExpandoObject. – supercat

1

Básicamente necesitará hacer algo de generación de código.

Escriba una aplicación de consola simple, o la aplicación de formas ganadoras, que carga la csv, luego toma la información de la csv y genera los archivos .cs.

+0

Creo que las quiere para generar en tiempo de ejecución, en lugar de tiempo de compilación, aunque la generación de código a través de una macro (o secuencia de comandos o lo que sea) sigue siendo una buena ruta. La generación en tiempo de ejecución puede ser necesaria si las propiedades cambian mientras la aplicación se está ejecutando. – FrustratedWithFormsDesigner

+1

Creo que se trata de tiempo de compilación, porque de lo contrario no tendría sentido tener propiedades reales y * no tener que escribir las declaraciones a mano *. Sin embargo. – OregonGhost

2

Code generation como esto se puede hacer de varias maneras diferentes.

  • Visual Studio tiene T4 templates.
  • Puede usar herramientas externas como My Generation (está orientado a generaciones de código ORM, no estoy seguro si es compatible con CSV).
  • O despliega tu propio código para leer el archivo y escribir dichas clases (se creará con un sufijo .generated.cs).
0

Esto es posible con el nuevo material dinámico en C# 4.0. No soy un experto, pero con objetos dinámicos puede definir el comportamiento cuando se evoca un método que no existe. This post muestra un ejemplo bastante divertido de cómo configurar un diccionario dinámico que podría hacer lo que desee.

1

Hay una solución fácil para eso, lea las propiedades en un diccionario y sobrecargar el operador del conjunto FileLoader 's:

public T this[string propertyName] 
{ 
    get { return yourDictionary[propertyName]; } 
} 

esta manera, se puede acceder a las propiedades utilizando fileLoadObject["SomePropertyName"].

Como señaló Oded, es es posible agregar propiedades dinámicamente con Reflection. Hay un ejemplo over here.

+1

¿Qué hay de la reflexión? Puedes crear objetos dinámicos con él. – Oded

+0

Gracias por la pista, no sabía de eso. – AndiDog

+0

@AndiDog - puede usar la reflexión para crear propiedades en C#. Tengo un código de ejemplo en algún lugar donde lo he usado, solo tengo que desenterrarlo –

2

Sin tener que actualizar su "FileLoader", y luego usar Reflection para acceder a las propiedades recién creadas, no hay manera de hacerlo.(Completley ignorar esta respuesta si buscas algo que funciona en Design/Tiempo de compilación, en lugar de en tiempo de ejecución =)

Lo que probablemente va a terminar haciendo es tener algo así como

public class FileLoader 
{ 
    // ... Other code for FileLoader goes here 

    public FileLoader(string propertiesFileNameAndPath) 
    { 
    // Load values from propertiesFile into _properties/_propertyValues 
    } 

    private _properties = new List<string>(); 
    private _propertyValues = new Dictionary<string, string>(); 

    public string[] Properties 
    { 
    // returning as an array stops your _properties being modified 
    return _properties.ToArray(); 
    } 
    public void UpdateProperty(string propertyName, string propertyValue) 
    { 
    if (propertyValues.ContainsKey(propertyName)) 
    { 
     propertyValues[propertyName] = propertyValue; 
    } 
    } 
    public string GetPropertyValue(string propertyValue) 
    { 
    if (propertyValues.ContainsKey(propertyName)) 
    { 
     return propertyValues[propertyName]; 
    } 
    } 
} 

Ahora puede hacer:

var fileLoader = new FileLoader("path to properties.csv"); 
foreach(var property in fileLoader.Properties) 
{ 
    var propertyValue = fileLoader.GetPropertyValue(property); 
} 

por supuesto, usted podría simplificarlo hasta cargarlo en un diccionario que regrese de un método de FileLoader, pero el código anterior mantiene parte de la "aparición" de la utilización de propiedades de la FileLoader clase =)

edición: Añadir "paso a paso" código

Una cosa que podría hacer que el limpiador de la sintaxis sería el uso de un "paso a paso", por lo que añadiría lo siguiente para FileLoader:

public string this[string index] 
    { 
    if (propertyValues.ContainsKey(propertyName)) 
    { 
     return propertyValues[propertyName]; 
    } 
    else 
    { 
     return null; 
    } 
    } 

a continuación, el código para accessint sería el un poco más ordenado:

var fileLoader = new FileLoader("path to properties.csv"); 
foreach(var property in fileLoader.Properties) 
{ 
    var propertyValue = fileLoader[property]; 
} 
+1

+1 para indexador. Eso es lo que pensé enseguida al leer la pregunta. –

1

Aquí hay una muestra usando ExpandoObject y C# 4.0 `s característica dinámica

public dynamic ParseCsvFile(string filePath) { 
    var expando = new ExpandoObject; 
    IDictionary<string,object> map = expando; 
    foreach (var line in File.ReadAllLines(filePath)) { 
    var array = line.Split(new char[]{','},2); 
    map.Add(array[0],array[1]); 
    } 
    return expando; 
} 

... 
var d = ParseCsvFile(someFilePath); 
Console.WriteLine(d.Property1); 
Cuestiones relacionadas