以编程方式生成属性

我想加载一个属性文件(它是一个.csv文件,每行都有一个名称和相关的数值),然后访问这些属性值,如: FileLoader.PropertyOneFileLoader.PropertyTwo 。 问题是我不想为每个值写一个属性,我希望它们是从文件生成的。 所以

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

不是我想要的。 这可能吗? 我看不到任何办法,因为显然编译器不会知道属性名称。 也许类似的东西?

在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的强大function是动态创建复杂的分层对象,但我认为即使对于简单的动态定义对象,您也可以使用它来获得shiny的语法。

编辑:这是SO的另一个答案,由编写之前链接文章的同一专栏作者添加有关ExpandoObject优点的详细信息

ExpandoObject的真正好处是什么?

像这样的代码生成可以通过几种不同的方式完成。

  • Visual Studio具有T4模板 。
  • 您可以使用My Generation等外部工具(它适用于ORM代码生成,不确定它是否支持CSV)。
  • 或者推出自己的代码来读取文件并写出这些类(用.generated.cs后缀创建)。

如果没有让你的“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(); private _propertyValues = new Dictionary(); 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; } } 

然后accessint的代码会稍微整洁:

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

这是使用ExpandoObject和C#的4.0动态特性的示例

 public dynamic ParseCsvFile(string filePath) { var expando = new ExpandoObject; IDictionary 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); 

你基本上需要做一些代码生成。

编写一个简单的控制台应用程序,或赢取表单应用程序,加载csv,然后从csv获取信息并生成.cs文件。

有一个简单的解决方案,将属性读入字典并重载FileLoader的数组运算符:

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

这样,您可以使用fileLoadObject["SomePropertyName"]访问属性。

正如Oded所指出的,可以使用Reflection动态添加属性。 这里有一个例子。

这可以通过c#4.0中的新动态内容实现。 我不是专家,但是对于动态对象,您可以定义不存在的方法时的行为。 这篇文章展示了一个非常有趣的例子,说明如何设置一个可以做你想要的动态字典。