Создание свойств программно
Я хочу загрузить файл свойств (это файл .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. Я не эксперт, но с динамическими объектами вы можете определить поведение, когда вызываемый метод не существует. Этот пост показывает довольно забавный пример того, как настроить динамический словарь, который может делать то, что вы хотите.