Get value of c# dynamic property via string

前端 未结 11 1720
孤城傲影
孤城傲影 2020-11-27 11:12

I\'d like to access the value of a dynamic c# property with a string:

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

相关标签:
11条回答
  • 2020-11-27 11:20
    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);
    }
    

    Add reference to Microsoft.CSharp. Works also for dynamic types and private properties and fields.

    Edit: While this approach works, there is almost 20× faster method from the Microsoft.VisualBasic.dll assembly:

    public static object GetProperty(object target, string name)
    {
        return Microsoft.VisualBasic.CompilerServices.Versioned.CallByName(target, name, CallType.Get);
    }
    
    0 讨论(0)
  • 2020-11-27 11:26

    To get properties from dynamic doc when .GetType() returns null, try this:

    var keyValuePairs = ((System.Collections.Generic.IDictionary<string, object>)doc);
    var val = keyValuePairs["propertyName"].ToObject<YourModel>;
    
    0 讨论(0)
  • 2020-11-27 11:32

    Dynamitey is an open source .net std library, that let's you call it like the dynamic keyword, but using the a string for the property name rather than the compiler doing it for you, and it ends up being equal to reflection speedwise (which is not nearly as fast as using the dynamic keyword, but this is due to the extra overhead of caching dynamically, where the compiler caches statically).

    Dynamic.InvokeGet(d,"value2");
    
    0 讨论(0)
  • 2020-11-27 11:34

    The GetProperty/GetValue does not work for Json data, it always generate a null exception, however, you may try this approach:

    Serialize your object using JsonConvert:

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

    Then access it directly casting it back to string:

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

    It may work straight applying the Convert.ToString(request)["DynamicFieldName"], however I haven't tested.

    0 讨论(0)
  • 2020-11-27 11:34

    Similar to the accepted answer, you can also try GetField instead of GetProperty.

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

    Depending on how the actual Type was implemented, this may work when GetProperty() doesn't and can even be faster.

    0 讨论(0)
  • 2020-11-27 11:35

    The easiest method for obtaining both a setter and a getter for a property which works for any type including dynamic and ExpandoObject is to use FastMember which also happens to be the fastest method around (it uses Emit).

    You can either get a TypeAccessor based on a given type or an ObjectAccessor based of an instance of a given type.

    Example:

    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");
    
    0 讨论(0)
提交回复
热议问题