C# 反射 - 使用反射从定界字符串填充 class 属性

C# Reflection - Populate class properties from delimited strings using reflection

我正在尝试使用从不规则 CSV 格式文件中检索的数据来填充 class。 我能够从文件中获取数据,确定文件中是否存在 属性 值,并根据检索到的数据创建对象。

尝试填充 class 属性时,我尝试过:

this.GetType().GetProperty(propName).SetValue(this, newProp);

...导致异常:

System.ArgumentException: 'Object of type 'System.Collections.Generic.List1[System.Collections.Generic.List1[SharpCodingTestApp.Bar]]' cannot be converted to type 'System.Collections.Generic.List`1[SharpCodingTestApp.Bar]'.'

和...

this.GetType().InvokeMember(propName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty, Type.DefaultBinder, this, new object[] { newProp });

...导致异常:

System.MissingMethodException: 'Method 'SharpCodingTestApp.Bar' not found.'

这是我目前的代码 运行:

public class FooBar
{
    private string _configFile;

    public Foo PropFoo { get; get; }
    public List<Bar> PropBar { get; set; }

    public void Load()
    {
        List<object> props = new List<object>();

        if (String.IsNullOrWhiteSpace(_configFile) != true)
        {
            //Does the config file contain all of the required settings?
            if (ConfigFileContainsRoomConfigSettings(_configFile))
            {
                //Get the information we need from the file.
                string[] configLines = GetConfigLines(_configFile);

                foreach (var line in configLines)
                {
                    var propName = line.Split(", ")[0].Trim(' ');
                    var newProp = CreatePropertyObejct(propName, line);
                    this.GetType().InvokeMember(propName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty, Type.DefaultBinder, this, new object[] { newProp });
                }
            }
        }
    }

    private object CreatePropertyObejct(string paramPropertyName, string paramPropertyConfigString)
    {
        var prop = this.GetType().GetProperty(paramPropertyName);
        if (prop.PropertyType.Name.ToLower().Contains("list") == true)
        {
            var listType = typeof(List<>);
            var constructedListType = listType.MakeGenericType(prop.PropertyType);
            return Activator.CreateInstance(constructedListType);
        }
        else
        {
            return Activator.CreateInstance(prop.PropertyType, paramPropertyConfigString, ',');
        }
    }
}

这是文件中的数据示例:

Foo, FooVal1, FooVal2
Bar, BarVal1, BarVal2, BarVal3, BarVal4
Bar, BarVal1, BarVal2, BarVal3, BarVal4

每个分隔字符串中的第一个值包含数据所属的 属性 名称。
Bar 在文件中有多个条目来表示列表中的每个对象。

如何解决异常以及是否有更好的方法来完成我想做的事情?

谢谢。

如果您正在编写反射代码,请不要求助于字符串比较。并尝试预先构建和缓存您需要的一切。但是,如果您不知道要问什么问题,就很难找到正确的方法。

发生第一个错误是因为 prop.PropertyType 已经是 List<T>,所以 typeof(List<>).MakeGenericType(prop.PropertyType) 正在定义 List<List<T>>

输入数据实际上是csv吗?数据可以包含引号、逗号和换行符吗?那么.Split(", ")就不剪了。您需要找到/实施合适的 C# 解析器。

我不太清楚您要对每个其他 csv 列做什么?