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.List
1[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 列做什么?
我正在尝试使用从不规则 CSV 格式文件中检索的数据来填充 class。 我能够从文件中获取数据,确定文件中是否存在 属性 值,并根据检索到的数据创建对象。
尝试填充 class 属性时,我尝试过:
this.GetType().GetProperty(propName).SetValue(this, newProp);
...导致异常:
System.ArgumentException: 'Object of type 'System.Collections.Generic.List
1[System.Collections.Generic.List
1[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 列做什么?