【问题标题】:Cast a property to its actual type dynamically using reflection使用反射将属性动态转换为实际类型
【发布时间】:2009-05-25 20:01:50
【问题描述】:

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

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

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

由于对象是由实体框架生成的,我无法将类型转换为接口并对其进行操作。

这是场景代码:

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

【问题讨论】:

  • 如何将其转换为您不知道的类型?你在运行时就知道了。所以只能作为对象来处理。
  • 你能解释一下你的场景吗?假设有一种方法可以动态执行(实际上没有,但是……)接下来你会用这个变量做什么?你不能调用 .IntProperty 因为你不知道它的类型,所以回到开头没有必要将它转换为 ClassA。您只需继续反射以获取 IntProperty 等等......
  • 强制转换在很大程度上是编译时的事情,而不是真正的反射事情。您究竟是什么意思,“将属性转换为实际类型”?有一些涉及泛型的选项,但如果没有明确的想法你想要实现什么,很难给出一个好的答案。即使使用泛型(通过MakeGenericMethod 等),您也只需将其作为T - 但这实际上并不能让您 很多......所以:你怎么办想要,一旦你输入它...
  • 你能澄清你的问题吗?因为我无法正确理解。
  • 框架中没有真正的动态转换。通常,此类问题可以使用接口或泛型来解决。

标签: c# entity-framework reflection


【解决方案1】:
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);  }

【讨论】:

  • 为什么 Convert.ChangeType 或只是强制转换是不够的?
  • @miguelmpn 正确转换 Enum 或处理 value == "1" || 这样的值不够聪明价值==“真”||价值==“开”|| value == "checked" as bool。
  • 请注意,如果value 没有实现IConvertible 接口,Convert.ChangeType(value, property.PropertyType); 仍然会失败。例如,如果 property.PropertyType 是一些 IEnumerable
【解决方案2】:

我有一些时间,所以我尝试使用 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; 
        }
    }
}

【讨论】:

  • 解决了我想计算 List 或 List> 甚至 List>> 中的条目的问题,但想要一种方法来覆盖所有这些,不管 ,以进行验证。
【解决方案3】:

一旦得到反射类型,就可以使用Convert.ChangeType()

【讨论】:

  • 抱歉打扰了这篇旧帖。这只是给了我一个object。动态类型如何在这里发挥作用?
【解决方案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 );
        

        //返回实例;

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-01-02
          • 1970-01-01
          • 2015-07-04
          • 2020-04-06
          • 2014-09-22
          • 1970-01-01
          相关资源
          最近更新 更多