Генерируйте свойства программно

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

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

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

10
задан Cœur 3 August 2017 в 09:03
поделиться

7 ответов

В 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?

15
ответ дан 3 December 2019 в 17:20
поделиться

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

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

Если ваш "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 =)

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

Одна вещь, которая может сделать синтаксис более чистым, - это использовать "Индексатор", поэтому вы должны добавить следующее в 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];
}
​​
2
ответ дан 3 December 2019 в 17:20
поделиться

Вот пример использования 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
ответ дан 3 December 2019 в 17:20
поделиться

По сути, вам нужно будет произвести генерацию кода.

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

1
ответ дан 3 December 2019 в 17:20
поделиться

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

0
ответ дан 3 December 2019 в 17:20
поделиться

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

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

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

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

1
ответ дан 3 December 2019 в 17:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: