Генерация свойств программно - PullRequest
10 голосов
/ 04 февраля 2010

Я хочу загрузить файл свойств (это файл .csv, имеющий в каждой строке имя и соответствующее числовое значение), а затем получить доступ к этим значениям свойств следующим образом: FileLoader.PropertyOne или FileLoader.PropertyTwo. Проблема в том, что я не хочу писать свойства для каждого значения, я хочу, чтобы они генерировались из файла. Так

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

это не то, что я ищу. Это возможно? Я не вижу никакого способа сделать это, потому что, очевидно, компилятор не будет знать об именах свойств. Возможно, что-то похожее?

Ответы [ 7 ]

15 голосов
/ 04 февраля 2010

В C # 4.0 вы можете использовать ExpandoObject , ссылка содержит хорошее объяснение и пару вариантов использования, например:

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

Хотя огромным преимуществом ExpandoObject является динамическое создание сложных иерархических объектов, я полагаю, вы могли бы использовать его в целом для его блестящего синтаксиса даже для простых динамически определенных объектов.

РЕДАКТИРОВАТЬ: Вот еще один ответ на SO, добавив подробности о преимуществах ExpandoObject того же обозревателя, который написал ранее связанную статью

Каковы истинные преимущества ExpandoObject?

2 голосов
/ 04 февраля 2010

Вот пример использования ExpandoObject и динамической функции C # `4.0 *

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);
2 голосов
/ 04 февраля 2010

Без того, чтобы ваш FileLoader фактически переписывал сам себя, а затем использовал Reflection для доступа к вновь созданным свойствам, на самом деле это не способ сделать это. (Полностью игнорируйте этот ответ, если вы ищете что-то, что работает во время проектирования / компиляции, а не во время выполнения =)

То, что вы, вероятно, в конечном итоге будете делать, это что-то вроде

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

Теперь вы можете сделать:

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

Конечно, вы можете просто упростить его до загрузки в словарь, который вы возвращаете из метода в FileLoader, но приведенный выше код поддерживает часть "внешнего вида" использования свойств класса FileLoader =)

Редактировать: добавить код "indexer"

Единственное, что может сделать синтаксис более чистым, - это использовать «индексатор», поэтому вы добавили бы в FileLoader следующее:

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

Тогда код для accessint будет чуть более аккуратным:

var fileLoader = new FileLoader("path to properties.csv");
foreach(var property in fileLoader.Properties)
{
  var propertyValue = fileLoader[property];
}
2 голосов
/ 04 февраля 2010

Генерация кода , как это может быть сделано несколькими различными способами.

  • Visual Studio имеет шаблонов T4 .
  • Вы можете использовать внешние инструменты, такие как My Generation (он предназначен для генерации кода ORM, но не уверен, что поддерживает CSV).
  • Или разверните свой собственный код для чтения файла и запишите такие классы (создаются с суффиксом .generated.cs).
1 голос
/ 04 февраля 2010

Для этого есть простое решение: прочитать свойства в словарь и перегрузить оператор массива FileLoader:

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

Таким образом, вы можете получить доступ к свойствам, используя fileLoadObject["SomePropertyName"].

Как указал Одед, позволяет динамически добавлять свойства с помощью Reflection. Вот пример здесь .

1 голос
/ 04 февраля 2010

В основном вам нужно будет выполнить генерацию кода.

Напишите простое консольное приложение или приложение win form, которое загружает CSV, затем берет информацию из CSV и генерирует файлы .cs.

0 голосов
/ 04 февраля 2010

Это возможно с новым динамическим материалом в c # 4.0. Я не эксперт, но с динамическими объектами вы можете определить поведение, когда вызывается несуществующий метод. Этот пост показывает довольно забавный пример того, как настроить динамический словарь, который может делать то, что вы хотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...