سؤال

I'm trying to retrive fields or properties from a dynamic class using reflection, but when I call the dynamic object using Getfield or GetProperty it can never find the field and none of the dynamic object.Try* methods are entered.

Not sure why this isn't working on .net4.

See below for testdyn dynamic test class.

I'm calling it like this :

        dynamic td = new testdyn();
        td.SendDebugEvent += new DebugDelegate(debug);
        td.test();

Getting these results :

one = -1 
two = -1 
fiddle = -1 
test = -1 
set: fiddle = 241827974 
fiddle = -1

Expect to see

one = 1
two = 2
fiddle = 3
test = -1
set: fiddle = 241827974
fiddle = 241827974

What am I doing wrong?

NOTE: it does work if I call 'td.fiddle'... but it seems strange that you wouldn't know the name to create the class but you would know it to access it??

from this post it seems that perhaps reflection isn't supported for dynamicobject since it implements idynamicmetaobjectprovider

How do I reflect over the members of dynamic object?

The issue is that this code is being used by external app that uses reflection.

let me know if you have ideas.

code follows.

   public delegate void DebugDelegate(string msg);
 public class testdyn : System.Dynamic.DynamicObject
    {
        List<string> items = new List<string>(new string[] { "one", "two", "fiddle", "my", "lou" });
        List<int> vals = new List<int>( new int[] { 1,2,3,5,8 });

        public event DebugDelegate SendDebugEvent;
        void debug(string msg)
        {
            if (SendDebugEvent!=null)
                SendDebugEvent(msg);
        }

        public void set(string name, int v)
        {
            var idx = items.IndexOf(name);
            if (idx < 0)
                return;
            vals[idx] = v;
            debug("set: " + name + " = " + v);
        }

    int get(string name)
    {
        object o = null;
        var t = GetType();
        try {
        o = t.GetProperty(name).GetValue(this, null);
        int v = (int)o;
        return v;
        } catch 
        {
            try
            {
                var f = t.GetField(name);
                o = f.GetValue(this);
                return (int)o;
            }
            catch 
            { 

            }
        }
        return -1;
    }

        string g(string name) { return name+" = "+get(name).ToString(); }
        Random r = new Random();
        public void test() { test(string.Empty); }
        public void test(string mytmp)
        {
            var t = GetType();
            // do some reads
            debug(g("one"));
            debug(g("two"));
            debug(g("fiddle"));
            debug(g("test"));
            // do some sets
            set("fiddle", r.Next());
            // they should change
            debug(g("fiddle"));
        }

        public override bool TryInvokeMember(System.Dynamic.InvokeMemberBinder binder, object[] args, out object result)
        {
            debug("got invoke member");
            return base.TryInvokeMember(binder, args, out result);
        }

        public override bool TrySetMember(System.Dynamic.SetMemberBinder binder, object value)
        {
            debug("got setmember");
            return base.TrySetMember(binder, value);
        }

        public override bool TryGetIndex(System.Dynamic.GetIndexBinder binder, object[] indexes, out object result)
        {
            debug("got getindex");
            return base.TryGetIndex(binder, indexes, out result);
        }

        public override bool TryGetMember(System.Dynamic.GetMemberBinder binder, out object result)
        {
            // get index of column value trying to be retrieved
            var idx = items.IndexOf(binder.Name);
            // default to empty
            result = string.Empty;
            // return error if we can't find
            if (idx < 0)
            {
                return base.TryGetMember(binder, out result);
            }
            // get result
            result = vals[idx];
            return true;
        }

        public override bool TryInvoke(System.Dynamic.InvokeBinder binder, object[] args, out object result)
        {
            debug("got invoke");
            return base.TryInvoke(binder, args, out result);
        }



        public override bool TryCreateInstance(System.Dynamic.CreateInstanceBinder binder, object[] args, out object result)
        {
            debug("got create instance");
            return base.TryCreateInstance(binder, args, out result);
        }

        public override IEnumerable<string> GetDynamicMemberNames()
        {
            debug("got member names");
            return items.ToArray();
        }
    }
هل كانت مفيدة؟

المحلول

Reflection does not work on dynamic properties, (although there may be a .net4.5 exception to this if you implement ICustomTypeProvider)

I wrote an open source DLR swiss army knive frameworkof sorts called ImpromptuInterface (available in nuget). In it I have a static method designed to bridge dynamic properties for the exact reason of external code using reflection to access properties dynamically. Impromptu.ActLikeProperties(this object originalDynamic, IDictionary<string, Type>propertySpec) ActLikeProperties.

The catch is that you need to provide a dictionary of property name & return types to my method and then pass the result to the external api, My method works by wrapping your DynamicObject with an emitted proxy that uses the dlr to forward the property calls you described in your dictionary from it's static definition to your dynamic type.

td.ActLikeProperties(new Dictionary<string,type>{{"one":typeof(int)},{"two":typeof(int) },{"fiddle":typeof(int) },{"test":typeof(int) }});
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top