我需要动态地将属性转换为其实际类型。我如何/可以使用反射来做到这一点?
解释我正在努力的真实场景。我试图在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
}
}
}
答案 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;