Search code examples
c#linqexpression-trees

Accessing property of an object whose type is known at runtime


I have an object whose base type is exposed to be at compile time, but whose runtime type is internal and for all practical purposes I am unable to get to the type at compile time.

However, I want to be able to access a property on its instance at runtime.

I understand that without knowing the type at compile time, I cannot create a typed delegate.

What is the most performant way of accessing this property? DynamicInvoke?

Imagine this is a file: Hidden.cs

 internal class Hidden
 {
     public string SomeProp { get { .. } }
 }

I can't type the following in my code Func someExpression = Expression.Lambda < Func < Program, string > > ...

I just want to confirm that my only option is DynamicInvoke when I can't reference the type at compile time.


Solution

  • You can create Func<object, string>, then cast the object to Hidden(your type) and then access SomeProp. All of this can be done in Expressions like this:

    internal class Program
    {
        private static Func<object, string> somePropFunc;
        private static void Main(string[] args)
        {
            //Create instance somehow
            Type type = typeof(Hidden);
            object hiddenInstance = Activator.CreateInstance(type);
    
            //Cache the delegate in static field, and use it any number of times
            somePropFunc = GetSomePropAccessorMethod();
            for (int i = 0; i < 100; i++)
            {
                // Access Hidden.SomeProp
                Console.WriteLine(somePropFunc(hiddenInstance));
            }
        }
    
        private static Func<object, string> GetSomePropAccessorMethod()
        {
            Type type = typeof(Hidden);
            PropertyInfo prop = type.GetProperty("SomeProp");
            var parameter = Expression.Parameter(typeof(object), "hidden");
            var castHidden = Expression.TypeAs(parameter, type);
            var propertyAccessor = Expression.Property(castHidden, prop);
            return Expression.Lambda<Func<object, string>>(propertyAccessor, parameter).Compile();
        }
    
    }
    
    internal class Hidden
    {
        public string SomeProp
        {
            get
            {
                return "Some text";
            }
        }
    }
    

    Which prints "Some text" in console 100 times.