通过字符串获取c#动态属性的值

时间:2011-02-08 22:59:33

标签: c# dynamic

我想使用字符串访问dynamic c#属性的值:

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

如果我只将“value2”作为字符串,我如何获得d.value2(“random”)的值?在javascript中,我可以使用d [“value2”]来访问值(“随机”),但我不知道如何使用c#和反射来执行此操作。我最接近的是:

d.GetType().GetProperty("value2") ...但我不知道如何从中获得实际价值。

一如既往,感谢您的帮助!

12 个答案:

答案 0 :(得分:191)

获得PropertyInfo(来自GetProperty)后,您需要调用GetValue并传入要从中获取值的实例。在你的情况下:

d.GetType().GetProperty("value2").GetValue(d, null);

答案 1 :(得分:36)

public static object GetProperty(object target, string name)
{
    var site = System.Runtime.CompilerServices.CallSite<Func<System.Runtime.CompilerServices.CallSite, object, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, name, target.GetType(), new[]{Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0,null)}));
    return site.Target(site, target);
}

添加对Microsoft.CSharp的引用。也适用于动态类型和私有属性和字段。

编辑:虽然这种方法有效,但 Microsoft.VisualBasic.dll 程序集的方法快了近20倍:

public static object GetProperty(object target, string name)
{
    return Microsoft.VisualBasic.CompilerServices.Versioned.CallByName(target, name, CallType.Get);
}

答案 2 :(得分:21)

Dynamitey是一个开源.net std库,让你像dynamic关键字一样调用它,但是使用字符串作为属性名,而不是编译器为你做,它最终成为equal to reflection speedwise(这并不像使用动态关键字那么快,但这是由于动态缓存的额外开销,编译器静态缓存)。

Dynamic.InvokeGet(d,"value2");

答案 3 :(得分:7)

在你要求动态对象的大部分时间里,你得到一个ExpandoObject(不在上面的问题的匿名但静态类型的例子中,但你提到JavaScript和我选择的JSON解析器JsonFx,生成一个,生成ExpandoObjects )。

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

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

答案 4 :(得分:6)

获取适用于任何类型(包括settergetter的属性的dynamicExpandoObject的最简单方法是使用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");

答案 5 :(得分:4)

  

d.GetType()。的getProperty( “值2”)

返回一个PropertyInfo对象。

然后再做

propertyInfo.GetValue(d)

答案 6 :(得分:4)

这是我获得dinamic属性值的方式:

    public dynamic Post(dynamic value)
    {            
        try
        {
            if (value != null)
            {
                var valorCampos = "";

                foreach (Newtonsoft.Json.Linq.JProperty item in value)
                {
                    if (item.Name == "valorCampo")//property name
                        valorCampos = item.Value.ToString();
                }                                           

            }
        }
        catch (Exception ex)
        {

        }


    }

答案 7 :(得分:3)

GetProperty / GetValue不适用于Json数据,它总是生成一个空异常,但是,您可以尝试这种方法:

使用JsonConvert序列化您的对象:

var z = Newtonsoft.Json.JsonConvert.DeserializeObject(Convert.ToString(request));

然后直接将其转换回字符串:

var pn = (string)z["DynamicFieldName"];

它可以直接应用Convert.ToString(请求)[&#34; DynamicFieldName&#34;],但我还没有经过测试。

答案 8 :(得分:1)

在.Net core 3.1中,您可以这样尝试

d?.value2 , d?.value3

答案 9 :(得分:0)

从动态文档获取属性 当.GetType()返回null时,请尝试以下操作:

var keyValuePairs = ((System.Collections.Generic.IDictionary<string, object>)doc);
var val = keyValuePairs["propertyName"].ToObject<YourModel>;

答案 10 :(得分:0)

类似于接受的答案,您也可以尝试使用GetField代替GetProperty

d.GetType().GetField("value2").GetValue(d);

取决于实际的Type的实现方式,当GetProperty()不起作用甚至更快时,这可能会起作用。

答案 11 :(得分:0)

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

辅助方法 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。