[英]Weird issue with setting value via reflection
我有这个辅助方法SetProperty ,它通过反射来设置对象的属性。 以下是我使用该方法的2种情况。 第一种方法CreateInstance可以很好地工作,但是第二种方法Insert不能工作。
在第二种方法中,一旦SetProperty方法返回,在对象上设置的属性就会丢失。 我已经通过Visual Studio对其进行了调试。 该对象的属性设置为直到最后一个大括号为止。 然后,当控件返回到调用方Insert时 ,Property值丢失。
设置属性的方法
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void SetProperty(object destination, string propertyName, object value)
{
var type = destination.GetType();
var property = type.GetProperty(propertyName);
var convertedVal = Convert(value, property.PropertyType);
property.SetValue(destination, convertedVal);
}
SetProperty方法在此方法中可以正常工作
public static T CreateInstance<T>(SqlDataReader row, IEnumerable<CLASS> columns)
{
var type = typeof(T);
var obj = Activator.CreateInstance(type, true);
foreach (var column in columns)
{
SetProperty(obj, column.BackingPropertyName, column.Name);
}
return (T)obj;
}
SetProperty方法在此方法中不起作用
public T Insert<T>(T obj, string table = null)
{
// CODE CHUNK
using (var conn = new SqlConnection(this.ConnectionString))
{
conn.Open();
using (var cmd = new SqlCommand(query.ToString(), conn))
{
// CODE CHUNK
var autoGeneratedValue = cmd.ExecuteScalar();
if (temp.AutoGeneratedColumn != null)
{
ReflectionHelper.SetProperty(
obj,
temp.AutoGeneratedColumn.BackingPropertyName,
autoGeneratedValue
);
}
}
}
return obj;
}
编辑-添加控制台应用程序以启用复制
要复制以创建新的控制台应用程序,然后将此代码粘贴到Program.cs中(或同等版本)
using System;
using System.Runtime.CompilerServices;
namespace ConsoleApplication1
{
public struct Person
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Gender { get; set; }
public int Age { get; set; }
}
internal class Program
{
private static void Main(string[] args)
{
var p = new Person
{
ID = 93
};
var res = SetProperty<Person>(ref p, "Age", 34);
Console.WriteLine(p.Age);
Console.WriteLine(res.Age);
Console.Read();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T SetProperty<T>(ref T destination, string propertyName, object value)
{
var type = destination.GetType();
var property = type.GetProperty(propertyName);
var convertedVal = Convert(value, property.PropertyType);
property.SetValue(destination, convertedVal);
return (T)destination;
}
private static object Convert(object source, Type destinationType)
{
if (destinationType == null)
{
throw new ArgumentNullException("destinationType");
}
if (destinationType.IsGenericType &&
destinationType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
if (source == null)
{
return null;
}
destinationType = Nullable.GetUnderlyingType(destinationType);
}
return System.Convert.ChangeType(source, destinationType);
}
}
}
从您的复制中,我可以看到问题所在。
这是由于您的Person
结构被装箱引起的。
在SetProperty<T>()
方法中考虑以下代码行:
property.SetValue(destination, convertedVal);
SetValue()
的第一个参数的类型为object
。 这意味着将struct destination
传递给它时,将其装箱,并在装箱的副本上设置属性-保留原始副本不变。 (请注意,装箱仅影响诸如结构之类的值类型-如果Person
是一个类,则不会装箱,并且可以按预期工作。)
要解决此问题,您必须通过将Person
结构体分配给object
来对其进行“手动”装箱,然后在该对象上设置属性,最后将其分配回原始结构体引用,如下所示:
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T SetProperty<T>(ref T destination, string propertyName, object value)
{
var type = destination.GetType();
var property = type.GetProperty(propertyName);
var convertedVal = Convert(value, property.PropertyType);
object boxed = destination;
property.SetValue(boxed, convertedVal);
destination = (T) boxed;
return (T)boxed;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.