Search code examples
c#genericscastingpropertyinfo

Cast a property to its actual type dynamically using reflection (where actual type is generic) v2


This is a slightly modified version of the question I asked before here.

The actual position is like below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace cns01
{
    class Program
    {
        public class DataFieldInfo2<T>
        {
            public bool IsSearchValue { get; set; } = false;
            public T Value { get; set; }
        }

        public class SmartRowVertrag
        {
            public DataFieldInfo2<int> ID { get; set; }
            public DataFieldInfo2<string> VSNR { get; set; }
        }

        static void Main(string[] args)
        {
            SmartRowVertrag tester = new SmartRowVertrag();
            tester.ID = new DataFieldInfo2<int>() { Value = 777, IsSearchValue = false };
            tester.VSNR = new DataFieldInfo2<string>() { Value = "234234234", IsSearchValue = true };

            var g = RetData3(tester);
        }

        public static object RetData3(object fsr)
        {
            object retVal = new object();
            var props = fsr.GetType().GetProperties();
            foreach (var prop in props)
            {
                PropertyInfo propInfo = prop.GetType().GetProperty("IsSearchValue"); // <-- here I get null
                propInfo = prop.PropertyType.GetProperty("IsSearchValue"); // here I get a propertyInfo, but...
                dynamic property = propInfo.GetValue(fsr, null); // ...<-- here fires error
                var result = property.IsSearchValue;
                if (result == true)
                {
                    // doThis
                }
            }
            return retVal;
        }
    }
}

I do need to get the boolean value stored in IsSearchValue to to accomplish things.

Thanks beforehand.

I mostly appreciate any helping answer.


Solution

  • fsr is the SmartRowVertrag. You're trying to get the IsSearchValue from that - but it doesn't exist.

    Instead, you'll need to call GetValue twice - once on prop, passing in fsr (so which is equivalent to using fsr.ID or dsr.VSNR) and then once on propInfo passing in the result of that first call.

    Next, your dynamic use is trying to get IsSearchValue on the result of propInfo.GetValue() - you're trying to evaluate something.IsSearchValue.IsSearchValue, effectively.

    Here's corrected code for that part:

    public static object RetData3(object fsr)
    {
        object retVal = new object();
        var props = fsr.GetType().GetProperties();
        foreach (var prop in props)
        {
            PropertyInfo propInfo = prop.PropertyType.GetProperty("IsSearchValue");
            if (propInfo != null)
            {
                object fieldInfo = prop.GetValue(fsr);
                object isSearchValue = propInfo.GetValue(fieldInfo);
                if (isSearchValue.Equals(true))
                {
                    Console.WriteLine($"{prop.Name} has a searchable field");
                }
            }
        }
        return retVal;
    }
    

    You could avoid using reflection twice though if you had either a non-generic interface that DataFieldInfo2<T> implemented, or a base class. For example:

    public interface IDataFieldInfo
    {
        bool IsSearchValue { get; }
    }
    
    public class DataFieldInfo2<T> : IDataFieldInfo
    {
        ...
    }
    

    You could then make your reflection code much clearer:

    public static object RetData3(object fsr)
    {
        var fieldProperties = fsr.GetType().GetProperties()
            .Where(prop => typeof(IDataFieldInfo).IsAssignableFrom(prop.PropertyType));
        foreach (var fieldProperty in fieldProperties)
        {
            var field = (IDataFieldInfo) fieldProperty.GetValue(fsr);
            if (field.IsSearchValue)
            {
                Console.WriteLine($"{fieldProperty.Name} is a search value field");
            }
        }
        
        // We don't actually know what you're trying to return
        return null;
    }