如何遍历自定义DynamicObject的属性值以生成CSV文件?
遍历自定义DynamicObject生成CSV并获取属性值的问题
我需要遍历自行创建的DynamicObject以生成CSV文件,以下是将CSV列标题和值加载到DynamicObject的代码:
int i = 0; MyDynamicObject myDynamicObject = new MyDynamicObject(); TestActionInfoLogOutCS.TestActionInfoLogOutRepository.Clear(); foreach (DataRow dr in TestActionInfoLogDT.Rows) { if (i == 0) { myDynamicObject.SetMember("TestInfoLogID", TestActionInfoLogOutCS.TestActionInfoLogOutRepository[0].TestInfoLogID.Value.ToString()); myDynamicObject.SetMember("TestInfoID", TestActionInfoLogOutCS.TestActionInfoLogOutRepository[0].TestInfoID.Value.ToString()); myDynamicObject.SetMember("TestDescription", TestActionInfoLogOutCS.TestActionInfoLogOutRepository[0].TestDescription.ToString()); myDynamicObject.SetMember("SPM_Barcode_UniqueValue", TestActionInfoLogOutCS.TestActionInfoLogOutRepository[0].ScannedInValue.ToString()); } if ((bool)dr["IsScanInValueRequiredFlag"]) myDynamicObject.SetMember((string)dr["Attribute"], TestActionInfoLogOutCS.TestActionInfoLogOutRepository[i].ScannedInValue.ToString()); if ((bool)dr["IsTesterScanRequiredFlag"]) myDynamicObject.SetMember((string)dr["Attribute"], TestActionInfoLogOutCS.TestActionInfoLogOutRepository[i].TesterIDSignOff.ToString()); i++; } var props = myDynamicObject.GetDynamicMemberNames().ToList();
我已在MyDynamicObject类中添加GetDynamicMemberNames重写方法:
public class MyDynamicObject : DynamicObject { Dictionary<string, object> _properties = new Dictionary<string, object>(); public object GetMember(string propName) { var binder = Binder.GetMember(CSharpBinderFlags.None, propName, this.GetType(), new List<CSharpArgumentInfo>{ CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)}); var callsite = CallSite<Func<CallSite, object, object>>.Create(binder); return callsite.Target(callsite, this); } public void SetMember(string propName, object val) { var binder = Binder.SetMember(CSharpBinderFlags.None, propName, this.GetType(), new List<CSharpArgumentInfo>{ CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)}); var callsite = CallSite<Func<CallSite, object, object, object>>.Create(binder); callsite.Target(callsite, this, val); } public override bool TryGetMember(GetMemberBinder binder, out object result) { string name = binder.Name.ToLower(); return _properties.TryGetValue(name, out result); } public override bool TrySetMember(SetMemberBinder binder, object value) { _properties[binder.Name.ToLower()] = value; return true; } public override IEnumerable<string> GetDynamicMemberNames() { return from p in _properties select p.Key; } }
目前我能够列出属性键名,但需要遍历属性值。当前的实现是直接访问私有字典_properties来获取键值对:
TestResultsCS testResultsCS = new TestResultsCS(); var keyList = myDynamicObject._properties.Keys.ToList(); var valList = myDynamicObject._properties.Values.ToList(); for (int x = 0; x < keyList.Count - 1; x++) { testResultsCS.Attribute = keyList[x].ToString(); testResultsCS.Value = valList[x].ToString(); testResultsCS.LoadTestResultsRespoistory(); }
我更希望通过TryGetValue方法直接从动态对象中获取值,但尝试的扩展方法未成功:
public static bool TryGetValue<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key, ref TValue value) { var result = dict.TryGetValue(key, out var foundValue); if (result) value = foundValue; return result; }
请问该如何实现这一需求?
解决方案
1. 给MyDynamicObject添加公开的TryGetValue方法
这是最简洁且符合封装原则的方案,直接在MyDynamicObject内部添加方法操作私有字典:
public class MyDynamicObject : DynamicObject { // 保留原有的所有代码... // 添加公开的TryGetValue方法 public bool TryGetValue(string key, out object value) { // 匹配TrySetMember中的小写转换逻辑 return _properties.TryGetValue(key.ToLower(), out value); } }
使用时直接遍历动态成员名并获取值:
TestResultsCS testResultsCS = new TestResultsCS(); foreach (var propName in myDynamicObject.GetDynamicMemberNames()) { if (myDynamicObject.TryGetValue(propName, out var value)) { testResultsCS.Attribute = propName; testResultsCS.Value = value.ToString(); testResultsCS.LoadTestResultsRespoistory(); } }
2. 使用动态类型直接访问属性
利用dynamic关键字直接获取动态属性值,无需额外方法:
TestResultsCS testResultsCS = new TestResultsCS(); dynamic dynObj = myDynamicObject; foreach (var propName in myDynamicObject.GetDynamicMemberNames()) { // 注意:需匹配存储时的小写转换逻辑 object value = dynObj.GetType().GetProperty(propName.ToLower())?.GetValue(dynObj); if (value != null) { testResultsCS.Attribute = propName; testResultsCS.Value = value.ToString(); testResultsCS.LoadTestResultsRespoistory(); } }
3. 实现IDictionary接口(不推荐)
若一定要用扩展方法,需让MyDynamicObject实现IDictionary<string, object>,将字典操作委托给内部私有成员:
public class MyDynamicObject : DynamicObject, IDictionary<string, object> { private Dictionary<string, object> _properties = new Dictionary<string, object>(); // 实现IDictionary的所有接口方法 public object this[string key] { get => _properties[key.ToLower()]; set => _properties[key.ToLower()] = value; } public ICollection<string> Keys => _properties.Keys; public ICollection<object> Values => _properties.Values; public int Count => _properties.Count; public bool IsReadOnly => false; public void Add(string key, object value) => _properties.Add(key.ToLower(), value); public void Add(KeyValuePair<string, object> item) => _properties.Add(item.Key.ToLower(), item.Value); public void Clear() => _properties.Clear(); public bool Contains(KeyValuePair<string, object> item) => _properties.Contains(new KeyValuePair<string, object>(item.Key.ToLower(), item.Value)); public bool ContainsKey(string key) => _properties.ContainsKey(key.ToLower()); public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex) => ((IDictionary<string, object>)_properties).CopyTo(array, arrayIndex); public IEnumerator<KeyValuePair<string, object>> GetEnumerator() => _properties.GetEnumerator(); public bool Remove(string key) => _properties.Remove(key.ToLower()); public bool Remove(KeyValuePair<string, object> item) => _properties.Remove(new KeyValuePair<string, object>(item.Key.ToLower(), item.Value)); public bool TryGetValue(string key, out object value) => _properties.TryGetValue(key.ToLower(), out value); IEnumerator IEnumerable.GetEnumerator() => _properties.GetEnumerator(); // 保留原有的DynamicObject重写方法... }
之后即可直接使用IDictionary自带的TryGetValue方法,无需额外扩展。
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

