以编程方式生成属性

11

我想要加载一个属性文件(它是一个CSV文件,在每个行上有一个名称和相关数值),然后可以像这样访问这些属性值:FileLoader.PropertyOneFileLoader.PropertyTwo。问题是我不想为每个值编写一个属性,我希望它们可以从文件中自动生成。

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

这不是我想要的。这个可行吗?我看不出有什么办法可以做到,因为编译器显然不会知道属性名。或许有类似的方法?


1
编写一个T4模板,根据.csv文件生成一个.cs文件。 - Mehrdad Afshari
7个回答

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 好处的详细信息

ExpandoObject 的真正好处是什么?


5
我认为这是一个例证"动态语言不好"的案例。没有智能感知,没有类型安全,没有编译时检查,会产生运行时异常 - 我认为代码生成会更好一些。 - OregonGhost
即使在ExpandoObject之前,人们也可以使用vb6中的“Dictionary”对象实现类似的结果,尽管“Dictionary”只能容纳类型为“Object”的内容:“MyDict!Address!Street = MyStreetObject”。在vb.net中也可以实现类似的功能,但是必须有最后一个对象的命名属性[例如st表示string]:“MyDict!Address!City.st =“Mercer Island””;这种方法可能具有与ExpandoObject相同的优缺点。 - supercat
如何添加方法? - Sathiyamoorthy

2

如果不是让你的“FileLoader”程序自己重写并使用反射来访问新创建的属性,实际上没有什么方法可以做到这一点。(如果你想在设计/编译时而不是运行时获得结果,请完全忽略此答案=)

你可能最终会做的是像以下这样的事情:

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

1
+1 是索引器。当我读到这个问题时,我立刻想到了这个。 - Wim

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

2
像这样的代码生成可以通过几种不同的方式完成。
  • Visual Studio有T4模板
  • 您可以使用外部工具,如My Generation(它针对ORM代码生成,不确定是否支持CSV)。
  • 或者编写自己的代码来读取文件并编写出这样的类(以.generated.cs为后缀创建)。

1

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

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

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

正如Oded所指出的那样,使用反射动态添加属性是可能的。这里有一个例子over here


1
反射怎么样?你可以用它创建动态对象。 - Oded
@AndiDog - 你可以使用反射在C#中创建属性。我有一些示例代码,只需要找出来就行了。 - Cody C
好的,我编辑了答案以提供正确的信息。我还添加了一个动态创建属性的教程。 - AndiDog

1

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

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


我认为他希望它们在运行时生成,而不是编译时生成,尽管通过宏(或脚本或其他方式)生成代码仍然是一个好的途径。如果属性在应用程序运行时发生变化,则可能需要运行时生成。 - FrustratedWithFormsDesigner
1
我认为这是关于编译时的问题,否则拥有真正的属性却不必手动编写声明就没有什么意义了。 - OregonGhost

0

在C# 4.0中,新的动态特性使这成为可能。虽然我不是专家,但使用动态对象,您可以定义当调用不存在的方法时的行为。此帖子展示了一个非常有趣的例子,说明如何设置一个动态字典来实现您想要的功能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接