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

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

Чтобы объяснить реальный сценарий, над которым я немного работаю. Я пытаюсь вызвать «Первый» метод расширения для свойства 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
        }
    }
}

Ответы [ 7 ]

32 голосов
/ 26 мая 2009
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);  }
6 голосов
/ 14 декабря 2009

У меня было некоторое время, поэтому я попытался решить свою проблему с помощью 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; 
        }
    }
}
3 голосов
/ 07 марта 2012

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

1 голос
/ 15 декабря 2010

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

1 голос
/ 04 июня 2009

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

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 может быть "хорошим" решением.

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

1 голос
/ 26 мая 2009

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

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

0 голосов
/ 01 июня 2017
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 );

// возвращаем экземпляр;

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...