locked
Custom DynamicObject terribly slow

    Question

  • Hello,

    I am trying to create custom DynamicObject because I need to be able to access private and internal members of some objects and it is not possible to access private members with default dynamic keyword assignment. The problem I have is terrible performance of my DynamicObject. While 10k loops on default dynamic run in about 50ms, on my custom type it runs in about 1600ms.

    Here is the code. The type TypeCache is not included, but it contains delegates used to read from or set member of the underlying object of my DynamicObject.

    public class PrivateDynamicObject : DynamicObject, IEquatable<PrivateDynamicObject> { private readonly object _value; private readonly Type _type; private readonly TypeCache _cache; public PrivateDynamicObject(object value) { _value = value; _type = value.GetType(); _cache = TypeCache.GetCache(_type); } public override bool TryGetMember(GetMemberBinder binder, out object result) { Func<object, object> d; if (_cache.Getters.TryGetValue(binder.Name, out d)) { result = d(_value); return true; } result = null; return false; } public override bool TrySetMember(SetMemberBinder binder, object value) { Action<object, object> d; if (_cache.Setters.TryGetValue(binder.Name, out d)) { d(_value, value); return true; } return false; } public bool Equals(PrivateDynamicObject other) { return other != null && _value.Equals(other._value); } public override bool Equals(object obj) { return _value.Equals(obj); } public override int GetHashCode() { return _value.GetHashCode(); } public override string ToString() { return _value.ToString(); } }

    The slowness comes from reading and setting the properties, instantiating the object is acceptable.
    Delegates used to set and get values are compiled using expression trees only once per type.

    Thanks

    EDIT: not 50s but 50ms


    Sunday, January 26, 2014 1:54 AM

Answers

  • I have found what was causing the slowness. When were the delegates to read and set members constructed they had to be converted to accept parameters of object type so I had to wrap generic delegates to delegates with object type parameters. And it was there where I forgot to extract compilation of expression tree from the resulting lambda. So the problem was recompiling the expression every time the field was accessed.
    • Marked as answer by Cookie Wookie Sunday, January 26, 2014 10:58 PM
    Sunday, January 26, 2014 10:58 PM

All replies

  • "an endless loop" - I would expect this to take longer than 50s to run :-)

    How is this class used?  Can you give an example of something that takes a long time to run?

    (I guess you already know that accessing private variables is a very, very bad idea)


    Paul Linton


    Sunday, January 26, 2014 7:30 AM
  • int n = 10000;
    Person p = new Person
    {
        Name = "John",
        Surname = "Smith",
        Address = new Address
        {
            Street = "123 Fake Street",
            City = "Springfield",
            ZIP = "925 01"
         }
    };
    
    PersonView pw = new PersonView();
    dynamic d1 = new PrivateDynamicObject(p); //p;
    dynamic d2 = new PrivateDynamicObject(pw); //pw;
    for (int i = 0; i < n; i++)
    {
         d2.Name = "s";
    }

    This is the test I used to measure performance of the class. It took 1600ms while without my object it took about 50ms. Now I see I misstyped in original question. There has to be 50ms not 50s. :)

    I know it is bad idea when you don't know the internals of the class but I am developing object mapper where the mappings can be specified in .cs files that are compiled at the start of the program and the types can be internal or private so I can't use static typing because it won't compile and normal dynamic keyword can't access private types' members.

    Sunday, January 26, 2014 12:22 PM
  • I have found what was causing the slowness. When were the delegates to read and set members constructed they had to be converted to accept parameters of object type so I had to wrap generic delegates to delegates with object type parameters. And it was there where I forgot to extract compilation of expression tree from the resulting lambda. So the problem was recompiling the expression every time the field was accessed.
    • Marked as answer by Cookie Wookie Sunday, January 26, 2014 10:58 PM
    Sunday, January 26, 2014 10:58 PM
  • Hello,

    I'm not sure for what exactly you need it but can't you use AutoMapper? might not be applicable to your case but otherwise, might save you some time.


    Regards,

    Eyal Shilony

    Monday, January 27, 2014 2:31 AM
    Moderator
  • I considered using AutoMapper too but I need to be able to change mapping without compiling the application.
    Monday, January 27, 2014 9:55 PM
  • @ritehere, please have respect to the contributors of this forum and behave yourself! if you have constructive comments you can use a clean language and discuss it politely, you don't have to disrespect the people here just because they made a mistake or think differently.

    Immature and nonconstructive posts won't be tolerated and will be deleted especially posts that aim to offend people in this forum.

    @Paul, You can just flag the posts and we will remove them.


    Regards, Eyal Shilony

    Monday, February 24, 2014 3:02 AM
    Moderator