以编程方式生成属性

时间:2010-02-04 16:18:36

标签: c# properties

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

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

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

7 个答案:

答案 0 :(得分:15)

在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优点的详细信息

What are the true benefits of ExpandoObject?

答案 1 :(得分:2)

这样的{p> Code generation可以通过几种不同的方式完成。

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

答案 2 :(得分:2)

如果没有让你的“FileLoader”实际重写,然后使用Reflection来访问新创建的属性,那么实际上并没有任何办法。 (如果您在设计/编译时工作,而不是在运行时=),那么Completley会忽略这个答案。

你最终可能会做的事情就是

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

答案 3 :(得分:2)

以下是使用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);

答案 4 :(得分:1)

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

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

答案 5 :(得分:1)

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

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

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

正如Oded所指出的那样, 可以用Reflection动态添加属性。有一个例子over here

答案 6 :(得分:0)

这可以通过c#4.0中的新动态内容实现。我不是专家,但对于动态对象,您可以定义不存在的方法时的行为。 This post显示了一个非常有趣的示例,说明如何设置可以执行所需操作的动态字典。