Создание свойств программно

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

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

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

Ответ 1

В С# 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 заключается в динамическом создании сложных иерархических объектов, я полагаю, вы могли бы использовать его в целом для этого блестящего sintax даже для простых динамически определенных объектов.

EDIT: Вот еще один ответ о том, что SO добавляет подробности о преимуществах ExpandoObject тем же обозревателем, который написал ранее связанную статью

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

Ответ 2

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

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

Ответ 3

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

Что вы, вероятно, в конечном итоге сделаете, это что-то вроде

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 =)

Изменить: добавить код индексатора

Одна вещь, которая могла бы сделать синтаксический очиститель, заключалась бы в использовании "индексатора", поэтому вы добавили бы следующее в FileLoader:

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

Тогда код для доступа к нему будет немного более аккуратным:

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

Ответ 4

Вам в основном нужно создать код.

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

Ответ 5

Там легко найти решение, прочитать свойства в словаре и перегрузить оператор массива FileLoader:

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

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

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

Ответ 6

Здесь пример с использованием динамической функции ExpandoObject и С# 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);

Ответ 7

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