Skip to content
This repository was archived by the owner on Mar 8, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 80 additions & 2 deletions CsvUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,41 @@ public static class CsvUtil {
}
return ret;
}

// class does not have a constructor with empty arguments
// like this
// class foo{
// string a {get;}
// public foo(string a){
// this.a = a;
// }
// }
public static List<T> LoadObjectsWithConstructor<T>(string filename, bool strict = true) {
using (var stream = File.OpenRead(filename)) {
using (var rdr = new StreamReader(stream)) {
return LoadObjectsWithConstructor<T>(rdr, strict);
}
}
}

public static List<T> LoadObjectsWithConstructor<T>(TextReader rdr, bool strict = true) {
var ret = new List<T>();
string header = rdr.ReadLine();
var fieldDefs = ParseHeader(header);
FieldInfo[] fi = typeof(T).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
PropertyInfo[] pi = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
string line;
while((line = rdr.ReadLine()) != null)
{
var args = new List<object>();
// box manually to avoid issues with structs
if (ParseLineToObject(line, fieldDefs, fi, pi, args, strict)) {
object obj = Activator.CreateInstance(typeof(T), BindingFlags.CreateInstance, null, args.ToArray(), null);
ret.Add((T)obj);
}
}
return ret;
}

// Load a CSV file containing fields for a single object from a file
// No header is required, but it can be present with '#' prefix
Expand Down Expand Up @@ -228,8 +263,9 @@ private static Dictionary<string, int> ParseHeader(string header) {
}

// Parse an object line based on the header, return true if any fields matched
private static bool ParseLineToObject(string line, Dictionary<string, int> fieldDefs, FieldInfo[] fi, PropertyInfo[] pi, object destObject, bool strict) {

private static bool ParseLineToObject(string line, Dictionary<string, int> fieldDefs, FieldInfo[] fi, PropertyInfo[] pi, object destObject, bool strict)
{

string[] values = EnumerateCsvLine(line).ToArray();
bool setAny = false;
foreach(string field in fieldDefs.Keys) {
Expand All @@ -243,6 +279,23 @@ private static bool ParseLineToObject(string line, Dictionary<string, int> field
}
return setAny;
}
private static bool ParseLineToObject(string line, Dictionary<string, int> fieldDefs, FieldInfo[] fi, PropertyInfo[] pi, List<object> args, bool strict)
{

string[] values = EnumerateCsvLine(line).ToArray();
bool setAny = false;
foreach(string field in fieldDefs.Keys) {
int index = fieldDefs[field];
if (index < values.Length) {
string val = values[index];
setAny = SetField(field, val, fi, pi, args) || setAny;
} else if (strict) {
Debug.LogWarning(string.Format("CsvUtil: error parsing line '{0}': not enough fields", line));
}
}
return setAny;
}


private static bool SetField(string fieldName, string val, FieldInfo[] fi, PropertyInfo[] pi, object destObject) {
bool result = false;
Expand All @@ -268,6 +321,31 @@ private static bool SetField(string fieldName, string val, FieldInfo[] fi, Prope
}
return result;
}

private static bool SetField(string fieldName, string val, FieldInfo[] fi, PropertyInfo[] pi, List<object> args) {
bool result = false;
foreach (PropertyInfo p in pi) {
// Case insensitive comparison
if (string.Compare(fieldName, p.Name, true) == 0) {
// Might need to parse the string into the property type
object typedVal = p.PropertyType == typeof(string) ? val : ParseString(val, p.PropertyType);
args.Add(typedVal);
result = true;
break;
}
}
foreach(FieldInfo f in fi) {
// Case insensitive comparison
if (string.Compare(fieldName, f.Name, true) == 0) {
// Might need to parse the string into the field type
object typedVal = f.FieldType == typeof(string) ? val : ParseString(val, f.FieldType);
args.Add(typedVal);
result = true;
break;
}
}
return result;
}

private static object ParseString(string strValue, Type t) {
var cv = TypeDescriptor.GetConverter(t);
Expand Down
30 changes: 29 additions & 1 deletion Editor/TestCsvUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,34 @@ public void TestLoadStruct() {

}


public class TestAutoImplementedClass
{
public ulong Id { get; }
public string Name { get; }

public TestAutoImplementedClass(ulong id, string name)
{
Id = id;
Name = name;
}
}

[Test]
public void TestLoadAutoImplementedPropertiesClass() {
//
var csvData = @"Id, Name
1,a
2,b";
List<TestAutoImplementedClass> objs;
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(csvData))) {
using (var sr = new StreamReader(ms)) {
objs = CsvUtil.LoadObjectsWithConstructor<TestAutoImplementedClass>(sr);
}
}
Assert.AreEqual(1, objs[0].Id);
Assert.AreEqual("a",objs[0].Name);
}
}
}
}