You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何遍历自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 16:57:08