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