我想用一个字符串访问一个动态c#属性的值:

动态d = new {value1 = "some", value2 = "random", value3 = "value"};

如果我只有“value2”作为字符串,我如何才能得到d.value2(“random”)的值?在javascript中,我可以做d["value2"]来访问值("random"),但我不确定如何用c#和反射来做到这一点。我最接近的说法是:

“value2”d.GetType () . getproperty()……但我不知道如何从中获得实际价值。

一如既往,谢谢你的帮助!


当前回答

如果你有一个动态变量,例如DapperRow,你可以先构建一个ExpandoObject,然后将Expando转换为一个IDictionary<string对象>。从那时起,可以通过属性名获取值。

帮助方法ToExpandoObject:

public static ExpandoObject ToExpandoObject(object value)
    {
        IDictionary<string, object> dapperRowProperties = value as IDictionary<string, object>;
        IDictionary<string, object> expando = new ExpandoObject();
        if (dapperRowProperties == null)
        {
            return expando as ExpandoObject;
        }
        foreach (KeyValuePair<string, object> property in dapperRowProperties)
        {
            if (!expando.ContainsKey(property.Key))
            {
                expando.Add(property.Key, property.Value);
            }
            else
            {
                //prefix the colliding key with a random guid suffixed 
                expando.Add(property.Key + Guid.NewGuid().ToString("N"), property.Value);
            } 
        }
        return expando as ExpandoObject;
    }

示例用法,我用粗体标记了赋予我们访问权限的类型转换,我用**字母标记了重要的位:

  using (var transactionScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
        {
            foreach (var dynamicParametersForItem in dynamicParametersForItems)
            {
                var idsAfterInsertion = (await connection.QueryAsync<object>(sql, dynamicParametersForItem)).ToList();
                if (idsAfterInsertion != null && idsAfterInsertion.Any())
                {
                    **var idAfterInsertionDict = (IDictionary<string, object>) ToExpandoObject(idsAfterInsertion.First());**
                    string firstColumnKey = columnKeys.Select(c => c.Key).First();
                    **object idAfterInsertionValue = idAfterInsertionDict[firstColumnKey];**
                    addedIds.Add(idAfterInsertionValue); //we do not support compound keys, only items with one key column. Perhaps later versions will return multiple ids per inserted row for compound keys, this must be tested.
                }
            }
        }

在我的示例中,我在动态对象DapperRow中查找一个属性值,并首先将Dapper行转换为ExpandoObject,并将其转换为一个字典属性包,如本文的其他回答中所示和提到的那样。

我的示例代码是我正在工作的Dapper扩展的InsertMany方法,我想在批量插入后抓住这里的多个id。

其他回答

d . GetType () GetProperty (value2”)。

返回PropertyInfo对象。

那就做吧

propertyInfo.GetValue(d)

很多时候,当您请求一个动态对象时,您会得到一个ExpandoObject(不是在上面问题的匿名但静态类型的示例中,但您提到了JavaScript和我选择的JSON解析器JsonFx,例如,生成ExpandoObject)。

如果您的动态实际上是一个ExpandoObject,您可以通过将其强制转换为IDictionary来避免反射,如http://msdn.microsoft.com/en-gb/library/system.dynamic.expandoobject.aspx所述。

一旦转换为IDictionary,就可以访问有用的方法,如.Item和.ContainsKey

在。net core 3.1中,你可以这样尝试

d?.value2 , d?.value3

为一个适用于任何类型的属性(包括dynamic和ExpandoObject)获取setter和getter的最简单方法是使用FastMember,这也是最快的方法(它使用Emit)。

您既可以获得基于给定类型的TypeAccessor,也可以获得基于给定类型实例的ObjectAccessor。

例子:

var staticData = new Test { Id = 1, Name = "France" };
var objAccessor = ObjectAccessor.Create(staticData);
objAccessor["Id"].Should().Be(1);
objAccessor["Name"].Should().Be("France");

var anonymous = new { Id = 2, Name = "Hilton" };
objAccessor = ObjectAccessor.Create(anonymous);
objAccessor["Id"].Should().Be(2);
objAccessor["Name"].Should().Be("Hilton");

dynamic expando = new ExpandoObject();
expando.Id = 3;
expando.Name = "Monica";
objAccessor = ObjectAccessor.Create(expando);
objAccessor["Id"].Should().Be(3);
objAccessor["Name"].Should().Be("Monica");

var typeAccessor = TypeAccessor.Create(staticData.GetType());
typeAccessor[staticData, "Id"].Should().Be(1);
typeAccessor[staticData, "Name"].Should().Be("France");

typeAccessor = TypeAccessor.Create(anonymous.GetType());
typeAccessor[anonymous, "Id"].Should().Be(2);
typeAccessor[anonymous, "Name"].Should().Be("Hilton");

typeAccessor = TypeAccessor.Create(expando.GetType());
((int)typeAccessor[expando, "Id"]).Should().Be(3);
((string)typeAccessor[expando, "Name"]).Should().Be("Monica");

如果你有一个动态变量,例如DapperRow,你可以先构建一个ExpandoObject,然后将Expando转换为一个IDictionary<string对象>。从那时起,可以通过属性名获取值。

帮助方法ToExpandoObject:

public static ExpandoObject ToExpandoObject(object value)
    {
        IDictionary<string, object> dapperRowProperties = value as IDictionary<string, object>;
        IDictionary<string, object> expando = new ExpandoObject();
        if (dapperRowProperties == null)
        {
            return expando as ExpandoObject;
        }
        foreach (KeyValuePair<string, object> property in dapperRowProperties)
        {
            if (!expando.ContainsKey(property.Key))
            {
                expando.Add(property.Key, property.Value);
            }
            else
            {
                //prefix the colliding key with a random guid suffixed 
                expando.Add(property.Key + Guid.NewGuid().ToString("N"), property.Value);
            } 
        }
        return expando as ExpandoObject;
    }

示例用法,我用粗体标记了赋予我们访问权限的类型转换,我用**字母标记了重要的位:

  using (var transactionScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
        {
            foreach (var dynamicParametersForItem in dynamicParametersForItems)
            {
                var idsAfterInsertion = (await connection.QueryAsync<object>(sql, dynamicParametersForItem)).ToList();
                if (idsAfterInsertion != null && idsAfterInsertion.Any())
                {
                    **var idAfterInsertionDict = (IDictionary<string, object>) ToExpandoObject(idsAfterInsertion.First());**
                    string firstColumnKey = columnKeys.Select(c => c.Key).First();
                    **object idAfterInsertionValue = idAfterInsertionDict[firstColumnKey];**
                    addedIds.Add(idAfterInsertionValue); //we do not support compound keys, only items with one key column. Perhaps later versions will return multiple ids per inserted row for compound keys, this must be tested.
                }
            }
        }

在我的示例中,我在动态对象DapperRow中查找一个属性值,并首先将Dapper行转换为ExpandoObject,并将其转换为一个字典属性包,如本文的其他回答中所示和提到的那样。

我的示例代码是我正在工作的Dapper扩展的InsertMany方法,我想在批量插入后抓住这里的多个id。