Подтвердить что ты не робот

Приведение свойства к его фактическому типу динамически с использованием отражения

Мне нужно динамически использовать свойство для его фактического типа. Как я/могу ли я сделать это с помощью отражения?

Чтобы объяснить реальный сценарий, над которым я немного работаю. Я пытаюсь вызвать метод расширения "Первый" в свойстве Entity Framework. Конкретное свойство, которое будет вызываться в контексте контекстного объекта Framework, передается в виде строки в метод (а также идентификатор записываемой записи). Поэтому мне нужен фактический тип объекта, чтобы вызвать метод First.

Я не могу использовать метод "Где" для объекта, поскольку метод лямбда или делегата по-прежнему нуждается в фактическом типе объекта для доступа к свойствам.

Также, поскольку объект генерируется платформой Entity Framework, я не могу отнести тип к интерфейсу и работать с ним.

Это код сценария:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Reflection;

namespace NmSpc
{

    public class ClassA
    {
        public int IntProperty { get; set; }
    }

    public class ClassB
    {
        public ClassA MyProperty { get; set; }
    }

    public class ClassC
    {
        static void Main(string[] args)
        {
            ClassB tester = new ClassB();

            PropertyInfo propInfo = typeof(ClassB).GetProperty("MyProperty");
            //get a type unsafe reference to ClassB`s property
            Object property = propInfo.GetValue(tester, null);

            //get the type safe reference to the property
            ClassA typeSafeProperty = property as ClassA;

            //I need to cast the property to its actual type dynamically. How do I/Can I do this using reflection?
            //I will not know that "property" is of ClassA apart from at runtime
        }
    }
}
4b9b3361

Ответ 1

У меня было какое-то время, поэтому я попытался решить свою проблему с помощью VS2010, и я думаю, что был прав ранее, когда я, хотя динамический ключ, "решал" мой вопрос. См. Код ниже.

using System.Reflection;

namespace TempTest
{
    public class ClassA
    {
        public int IntProperty { get; set; }
    }

    public class ClassB
    {
        public ClassB()
        {
            MyProperty = new ClassA { IntProperty = 4 };
        }
        public ClassA MyProperty { get; set; }
    }

    public class Program
    {
        static void Main(string[] args)
        {
            ClassB tester = new ClassB();

            PropertyInfo propInfo = typeof(ClassB).GetProperty("MyProperty");
            //get a type unsafe reference to ClassB`s property
            dynamic property = propInfo.GetValue(tester, null);

            //casted the property to its actual type dynamically
            int result = property.IntProperty; 
        }
    }
}

Ответ 2

public object CastPropertyValue(PropertyInfo property, string value) { 
if (property == null || String.IsNullOrEmpty(value))
    return null;
if (property.PropertyType.IsEnum)
{
    Type enumType = property.PropertyType;
    if (Enum.IsDefined(enumType, value))
        return Enum.Parse(enumType, value);
}
if (property.PropertyType == typeof(bool))
    return value == "1" || value == "true" || value == "on" || value == "checked";
else if (property.PropertyType == typeof(Uri))
    return new Uri(Convert.ToString(value));
else
    return Convert.ChangeType(value, property.PropertyType);  }

Ответ 3

Как только вы получите отраженный тип, вы можете использовать Convert.ChangeType().

Ответ 4

Наличие переменной определенного типа действительно полезно только во время компиляции и не поможет вам во время выполнения использовать ее таким образом. Попробуйте написать код, в котором вы будете использовать это... вы обнаружите, что он продолжает настаивать на необходимости знать тип, чтобы скомпилировать время на каком-то уровне (возможно, дальше вверх по цепочке вызовов, но вам все равно придется вводить тип конкретный тип, чтобы это было полезно).

Однако нужно иметь в виду, что если ваш тип является ссылочным типом, объект по-прежнему является типом, который вы создали. Не похоже, что есть преимущество в том, что объект сохраняется как ваш тип против объекта. Это красота отражения (а также часть того, почему она работает). Действительно нет причин пытаться "изменить" его тип во время выполнения в роли, так как он все еще будет объектом.

Ответ 5

Хотя я должен опубликовать решение проблемы реального мира.

string objectType = "MyProperty";

using (MyEntitiesContext entitiesContext = new MyEntitiesContext())
{
try
{
    string queryString = @"SELECT VALUE " + objectType+  " FROM MyEntitiesContext." + objectType + " AS " + objectType + " WHERE " + objectType + ".id = @id";

    IQueryable<Object> query = entitiesContext.CreateQuery<Object>(queryString, new ObjectParameter("id", objectId));

    foreach (Object result in query)
    {
        return result;
    }
}
catch (EntitySqlException ex)
{
    Console.WriteLine(ex.ToString());
}
}

return null;

Я думаю, что новый динамический ключ CLR4 может быть "хорошим" решением.

Спасибо за все ответы.

Ответ 6

Как установить значение корня в качестве строки, а затем переносить его как строку до тех пор, пока вам не понадобится преобразовать его в целевой тип?

Ответ 7

Type resultType = typeof(T);
IEnumerable<PropertyDescriptor> properties = TypeDescriptor.GetProperties(resultType).Cast<PropertyDescriptor>();

object instance = Activator.CreateInstance(resultType);

var objValue = "VALUE FOR HEADER";
var resultHeader = "HeaderName";
var prop = properties.Single(p => string.Equals(p.Name, resultHeader, StringComparison.InvariantCultureIgnoreCase));

var targetType = Nullable.GetUnderlyingType(prop.PropertyType) !=null Nullable.GetUnderlyingType(prop.PropertyType):prop.PropertyType;

objValue  = Convert.ChangeType(objValue , targetType);
prop.SetValue(instance, objValue );

//вернуть экземпляр