C#,收集 class 个字段
C#, Making a collection of class fields
有没有办法收集现有 class 个字段?
我有一个 class 有很多 fields/properties 各种类型的有意义的名字。
class ExampleClass
{
public string meaningfulName1 { get; set;}
public double meaningfulName2 { get; set;}
...
public myOtherClass meaningfulNameN { get; set;}
}
我需要从外部(不是我的)程序生成的文件中读取这些属性的值。
因为有很多fields/properties,读取值并一一分配似乎效率低下。所以我想要这些 fields/properties 的集合。像
foreach (fieldReference in ExampleClass.fieldReferenceCollection)
{
readValueFromFile(fieldReference);
}
但是如何在保留所有名称的同时制作一个呢?
创建一个包含所有参数值而不是单独字段的集合似乎合乎逻辑,但字段名称会丢失。而且,考虑到字段的数量,我们希望尽可能保留这些名称以简化进一步的开发。
所以我需要单独的 fields/properties 和它们的集合同时可用。
据我所知,字典收集速度并不快,因此参数名称作为值的键似乎也不完全合适。
我找到的另一个选项是反射,但我还不确定反射集合中的字段顺序是如何确定的。字段顺序非常重要,因为我正在从中读取值的文件没有元数据,只有一系列十六进制值。此外,反射对于从文件中读取值似乎有点矫枉过正,而且它也很慢,afaik。
所以问题是:我应该怎么做才能同时拥有 class 个字段和它们的集合?
我对这个任务的假设是错误的吗?是否有任何其他方法可以将文件中的大量哑值读取到复杂对象中?
P.S。我的第一个 SO 问题,英语是我的第二语言,所以我对错误感到抱歉。
看来你必须使用反射来做你想做的事。至于确定字段的顺序,我建议使用自定义属性标记属性。
举个例子。希望这会引导您找到所需的解决方案。
namespace ConsoleApplication2
{
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public sealed class FileField : Attribute
{
public int Index { get; set; }
public FileField() { }
}
class ExampleClass
{
[FileField(Index = 0)]
public string meaningfulName1 { get; set; }
[FileField(Index = 2)]
public double meaningfulName2 { get; set; }
[FileField(Index = 1)]
public MyOtherClass meaningfulNameN { get; set; }
}
class MyOtherClass
{
public string Something { get; set; }
}
class Program
{
static void Main(string[] args)
{
var exampleClassFieldProperties = GetExampleClassFieldProperties();
var lines = File.ReadAllLines("datafile.txt");
var records = new List<ExampleClass>();
foreach (var line in lines)
{
var fields = line.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
var record = new ExampleClass();
for(int fieldIndex = 0; fieldIndex < fields.Length; fieldIndex++)
{
if (exampleClassFieldProperties.ContainsKey(fieldIndex))
{
ReadValueFromFile(fields[fieldIndex], exampleClassFieldProperties[fieldIndex], record);
}
}
records.Add(record);
}
Console.WriteLine("Press any key to continue");
Console.ReadKey();
}
public static Dictionary<int, PropertyInfo> GetExampleClassFieldProperties()
{
var exampleClassFieldProperties = new Dictionary<int, PropertyInfo>();
var properties = typeof(ExampleClass).GetProperties();
foreach (var property in properties)
{
var attributes = property.GetCustomAttributes(false);
int index = 0;
foreach (var attribute in attributes)
{
if (attribute is FileField)
{
index = ((FileField)attribute).Index;
if (exampleClassFieldProperties.ContainsKey(index) == false)
{
exampleClassFieldProperties.Add(index, property);
}
}
}
}
return exampleClassFieldProperties;
}
public static void ReadValueFromFile(string field, PropertyInfo exampleClassField, ExampleClass record)
{
if (exampleClassField.PropertyType.Name == typeof(string).Name)
{
record.GetType().InvokeMember(exampleClassField.Name,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
Type.DefaultBinder, record, new object[] { field });
}
else if (exampleClassField.PropertyType.Name == typeof(double).Name)
{
record.GetType().InvokeMember(exampleClassField.Name,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
Type.DefaultBinder, record, new object[] { double.Parse(field) });
}
else if (exampleClassField.PropertyType.Name == typeof(MyOtherClass).Name)
{
var other = new MyOtherClass();
// TO DO: Parse field to set properties in MyOtherClas
record.GetType().InvokeMember(exampleClassField.Name,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
Type.DefaultBinder, record, new object[] { other });
}
}
}
}
有没有办法收集现有 class 个字段?
我有一个 class 有很多 fields/properties 各种类型的有意义的名字。
class ExampleClass
{
public string meaningfulName1 { get; set;}
public double meaningfulName2 { get; set;}
...
public myOtherClass meaningfulNameN { get; set;}
}
我需要从外部(不是我的)程序生成的文件中读取这些属性的值。
因为有很多fields/properties,读取值并一一分配似乎效率低下。所以我想要这些 fields/properties 的集合。像
foreach (fieldReference in ExampleClass.fieldReferenceCollection)
{
readValueFromFile(fieldReference);
}
但是如何在保留所有名称的同时制作一个呢?
创建一个包含所有参数值而不是单独字段的集合似乎合乎逻辑,但字段名称会丢失。而且,考虑到字段的数量,我们希望尽可能保留这些名称以简化进一步的开发。
所以我需要单独的 fields/properties 和它们的集合同时可用。
据我所知,字典收集速度并不快,因此参数名称作为值的键似乎也不完全合适。
我找到的另一个选项是反射,但我还不确定反射集合中的字段顺序是如何确定的。字段顺序非常重要,因为我正在从中读取值的文件没有元数据,只有一系列十六进制值。此外,反射对于从文件中读取值似乎有点矫枉过正,而且它也很慢,afaik。
所以问题是:我应该怎么做才能同时拥有 class 个字段和它们的集合?
我对这个任务的假设是错误的吗?是否有任何其他方法可以将文件中的大量哑值读取到复杂对象中?
P.S。我的第一个 SO 问题,英语是我的第二语言,所以我对错误感到抱歉。
看来你必须使用反射来做你想做的事。至于确定字段的顺序,我建议使用自定义属性标记属性。
举个例子。希望这会引导您找到所需的解决方案。
namespace ConsoleApplication2
{
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public sealed class FileField : Attribute
{
public int Index { get; set; }
public FileField() { }
}
class ExampleClass
{
[FileField(Index = 0)]
public string meaningfulName1 { get; set; }
[FileField(Index = 2)]
public double meaningfulName2 { get; set; }
[FileField(Index = 1)]
public MyOtherClass meaningfulNameN { get; set; }
}
class MyOtherClass
{
public string Something { get; set; }
}
class Program
{
static void Main(string[] args)
{
var exampleClassFieldProperties = GetExampleClassFieldProperties();
var lines = File.ReadAllLines("datafile.txt");
var records = new List<ExampleClass>();
foreach (var line in lines)
{
var fields = line.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
var record = new ExampleClass();
for(int fieldIndex = 0; fieldIndex < fields.Length; fieldIndex++)
{
if (exampleClassFieldProperties.ContainsKey(fieldIndex))
{
ReadValueFromFile(fields[fieldIndex], exampleClassFieldProperties[fieldIndex], record);
}
}
records.Add(record);
}
Console.WriteLine("Press any key to continue");
Console.ReadKey();
}
public static Dictionary<int, PropertyInfo> GetExampleClassFieldProperties()
{
var exampleClassFieldProperties = new Dictionary<int, PropertyInfo>();
var properties = typeof(ExampleClass).GetProperties();
foreach (var property in properties)
{
var attributes = property.GetCustomAttributes(false);
int index = 0;
foreach (var attribute in attributes)
{
if (attribute is FileField)
{
index = ((FileField)attribute).Index;
if (exampleClassFieldProperties.ContainsKey(index) == false)
{
exampleClassFieldProperties.Add(index, property);
}
}
}
}
return exampleClassFieldProperties;
}
public static void ReadValueFromFile(string field, PropertyInfo exampleClassField, ExampleClass record)
{
if (exampleClassField.PropertyType.Name == typeof(string).Name)
{
record.GetType().InvokeMember(exampleClassField.Name,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
Type.DefaultBinder, record, new object[] { field });
}
else if (exampleClassField.PropertyType.Name == typeof(double).Name)
{
record.GetType().InvokeMember(exampleClassField.Name,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
Type.DefaultBinder, record, new object[] { double.Parse(field) });
}
else if (exampleClassField.PropertyType.Name == typeof(MyOtherClass).Name)
{
var other = new MyOtherClass();
// TO DO: Parse field to set properties in MyOtherClas
record.GetType().InvokeMember(exampleClassField.Name,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
Type.DefaultBinder, record, new object[] { other });
}
}
}
}