![](/img/trans.png)
[英]Alternatives to using property.setvalue() for efficiency purposes
[英]Reflection Property.SetValue(
我有以下類可以從分隔行創建對象:
public class Mapper<T>
{
public T Map(string line, char delimiter)
{
if(String.IsNullOrEmpty(line))
throw new ArgumentNullException(nameof(line));
if (Char.IsWhiteSpace(delimiter))
throw new ArgumentException(nameof(delimiter));
var splitString = line.Split(delimiter);
var properties = typeof(T).GetProperties();
if(properties.Count() != splitString.Count())
throw new InvalidOperationException($"Row has {splitString.Count()} columns but object has {properties.Count()}.");
var obj = Activator.CreateInstance<T>();
for (var i = 0; i < splitString.Count(); i++)
{
var prop = properties[i];
var propType = prop.PropertyType;
var valType = Convert.ChangeType(splitString[i], propType);
prop.SetValue(obj, valType);
}
return (T)obj;
}
}
如果我使用分隔字符串調用 map 方法,它將使用行中的分隔值填充對象上的所有屬性。
但是,當我從以下調用它時:
public class CsvStreamReader<T>
{
private readonly Mapper<T> _mapper;
public CsvStreamReader(Mapper<T> mapper)
{
_mapper = mapper;
}
public IEnumerable<T> ReadCsvFile(string filePath, bool hasHeader)
{
if(hasHeader)
return File.ReadAllLines(filePath)
.Skip(1)
.Select(x => _mapper.Map(x, ','));
return File.ReadAllLines(filePath)
.Select(x => _mapper.Map(x, ','));
}
}
它將返回一個 T 列表,但所有屬性都將為空並且不會被設置。
更新:剛剛意識到我的班級不是班級,而是實際上是一個結構體。
當T
是值類型時,為了使您的Mapper<T>
工作,您需要在裝箱為 object 時設置其屬性。 使用非通用的Activator.CreateInstance(typeof(T))
將您的obj
創建為object
,使用反射設置其屬性,然后在返回時最終將其轉換為所需的類型:
public class Mapper<T>
{
readonly List<PropertyInfo> properties = typeof(T).GetProperties().OrderBy(p => p.Name).ToList();
public T Map(string line, char delimiter)
{
if (String.IsNullOrEmpty(line))
throw new ArgumentNullException("line");
if (Char.IsWhiteSpace(delimiter))
throw new ArgumentException("delimiter");
var splitString = line.Split(delimiter);
if (properties.Count() != splitString.Count())
throw new InvalidOperationException(string.Format("Row has {0} columns but object has {1}", splitString.Count(), properties.Count()));
// Create as a reference (boxed if a value type).
object obj = Activator.CreateInstance(typeof(T));
// Set the property values on the object reference.
for (var i = 0; i < splitString.Count(); i++)
{
var prop = properties[i];
var propType = prop.PropertyType;
var valType = Convert.ChangeType(splitString[i], propType);
prop.SetValue(obj, valType);
}
// Cast to the return type unboxing if required.
return (T)obj;
}
}
樣品小提琴。
請注意,您的代碼不應依賴於Type.GetProperties()
返回的屬性順序。 從文檔:
GetProperties 方法不以特定順序返回屬性,例如字母順序或聲明順序。 您的代碼不得依賴於返回屬性的順序,因為該順序會有所不同。
因此,我修改了您的代碼以按名稱排序。 您可以選擇另一種策略,例如對數據協定類型使用數據成員順序。
最后,您可能想重新考慮使用可變結構的設計,請參閱為什么可變結構是“邪惡的”? 出於某些原因。 要將您的Mapper<T>
限制為僅適用於引用類型,您可以添加以下where
約束:
public class Mapper<T> where T : class
{
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.