使用反射动态地将属性转换为其实际类型

时间:2009-05-25 20:01:50

标签: c# entity-framework reflection

我需要动态地将属性转换为其实际类型。我如何/可以使用反射来做到这一点?

解释我正在努力的真实场景。我试图在Entity Framework属性上调用“First”扩展方法。要在Framework上下文对象上调用的特定属性作为字符串传递给方法(以及要检索的记录的id)。所以我需要对象的实际类型才能调用First方法。

我不能在对象上使用“Where”方法,因为lambda或delegate方法仍然需要对象的实际类型才能访问属性。

同样,当实体框架生成对象时,我无法将类型转换为接口并对其进行操作。

这是方案代码:

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 个答案:

答案 0 :(得分:32)

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);  }

答案 1 :(得分:5)

我有一些时间,所以我尝试使用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 :(得分:3)

获得反射类型后,您可以使用Convert.ChangeType()

答案 3 :(得分:1)

拥有特定类型的变量实际上仅在编译时有用,并且在运行时不会以这种方式使用它。尝试编写你将利用它的代码...你会发现它不断推动需求知道在某个级别编译时间的类型(可能在调用链的更上方,但你仍然需要输入具体的具体类型是有用的。)

但要记住一件事 - 如果您的类型是引用类型,则该对象仍然是您创建的类型。将对象保存为类型与对象相比,这并不是一件好事。这是反思之美(以及它起作用的部分原因)。实际上没有理由在演员表中尝试“改变”它的类型,因为它仍然是一个对象。

答案 4 :(得分:1)

虽然我应该将解决方案发布到现实世界的问题上。

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动态关键字可能是“不错”的解决方案。

感谢所有回复。

答案 5 :(得分:1)

如何将根值设置为字符串,然后将其作为字符串携带,直到需要将其转换为目标类型?

答案 6 :(得分:0)

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 );

// return instance;