How to set a property of a C# 4 dynamic object when you have the name in another variable

后端 未结 5 539
独厮守ぢ
独厮守ぢ 2021-02-01 13:38

I\'m looking for a way to modify properties on a dynamic C# 4.0 object with the name of the property known only at runtime.

Is there a way to do something l

相关标签:
5条回答
  • 2021-02-01 13:55

    Paul Sasik answered a similar question at C# 4.0 Dynamic vs Expando... where do they fit?

    using System;
    using System.Dynamic;
    
    class Program
    {
        static void Main(string[] args)
        {
            dynamic expando = new ExpandoObject();
            var p = expando as IDictionary<String, object>;
            p["A"] = "New val 1";
            p["B"] = "New val 2";
    
            Console.WriteLine(expando.A);
            Console.WriteLine(expando.B);
        }
    }
    
    0 讨论(0)
  • 2021-02-01 14:07

    To add to Jonas' answer, you don't have to create a new var p. Use this approach instead:

    using System;
    using System.Dynamic;
    
    class Program
    {
        static void Main(string[] args)
        {
            dynamic expando = new ExpandoObject();
            ((IDictionary<String, object>)expando)["A"] = "New val 1";
            ((IDictionary<String, object>)expando)["B"] = "New val 2";
    
            Console.WriteLine(expando.A);
            Console.WriteLine(expando.B);
        }
    }
    
    0 讨论(0)
  • 2021-02-01 14:08

    My open source framework Dynamitey has methods for invoking based on string names using the DLR. It does the work of caching binding sites and streamlines it down to one method call. it also runs faster than reflection on non-dynamic objects too.

    Dynamic.InvokeSet(e, "TestKey", "value");
    
    0 讨论(0)
  • 2021-02-01 14:08

    fast-member may fit the bill - it looks like it generates the IL on the fly, but caches it so it's really fast after the first use.

    0 讨论(0)
  • 2021-02-01 14:09

    Not very easily, no. Reflection doesn't work, since it assumes a regular type model, which is not the full range of dynamic. If you are actually just talking to regular objects, then just use reflection here. Otherwise, I expect you may want to reverse-engineer the code that the compiler emits for a basic assignment, and tweak it to have a flexibly member-name. I'll be honest, though: this isn't an attractive option; a simple:

    dynamic foo = ...
    foo.Bar = "abc";
    

    translates to:

    if (<Main>o__SiteContainer0.<>p__Site1 == null)
    {
        <Main>o__SiteContainer0.<>p__Site1 = CallSite<Func<CallSite, object, string, object>>.Create(Binder.SetMember(CSharpBinderFlags.None, "Bar", typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType, null) }));
    }
    <Main>o__SiteContainer0.<>p__Site1.Target(<Main>o__SiteContainer0.<>p__Site1, foo, "abc");
    

    If you want an approach that works for both dynamic and non-dynamic objects: FastMember is handy for this, and works at either the type or object level:

    // could be static or DLR 
    var wrapped = ObjectAccessor.Create(obj); 
    string propName = // something known only at runtime 
    Console.WriteLine(wrapped[propName]);
    

    available on Nuget, and heavily optimised for both dynamic and non-dynamic scenarios.

    0 讨论(0)
提交回复
热议问题