缓存reflection结果(类属性)

考虑到不应该重新评估相当静态的数据而是缓存,我想知道是否可以使用Reflection来获取类属性一次,然后缓存它们以便我可以动态评估对象属性和读取/赋值,但不是每次我这样做都会有reflection开销。 这可能吗(示例代码?)?

为了澄清一点,让我说我有这个课程:

public class Cloud { Boolean IsWhite; } 

而我正在尝试制作一个方法,允许我做这样的事情(伪代码):

 Update(myCloudInstance, new {IsWhite, true}); 

如果现在更新已经知道云的属性(typeof(myCloudInstance)),则应首先检查缓存,然后使用缓存信息将属性“IsWhite”赋值为“true”,而不是再次执行Reflection。

关于如何做到这一点的任何想法?

目前尚不清楚你正在做什么,但缓存肯定会对reflection产生影响。

特别是,如果你正在调用方法(或属性getter / setter)并且可以以类型安全的方式这样做,就调用代码而言,如果你将MethodInfo转换为强大的方法,它可以产生巨大的差异。键入一次委托,然后重用它。

如果你能给我们一个完整的例子来说明你想要做什么,这将有助于我们提出更具体的想法甚至代码。 如果你只是要缓存一个可能没有那么多(或任何)效果的PropertyInfo ,那么正常的Type.GetProperty (etc)方法可能已经非常快了。 与性能问题一样,关键是衡量你实际在做什么。 进行更改并再次测量等

反思的成本不需要像你想象的那么大。 除了代表(Jon讨论过)之外,您还可以使用HyperDescriptor之类的东西来最大限度地降低reflection成本,而无需更改代码 – 它只是变成了PropertyDescriptor

 PropertyDescriptorCollection props = TypeDescriptor.GetProperties(myCloudInstance); // ideally cache props, but not essential 

然后

 object val = props["IsWhite"].GetValue(myCloudInstance); 

或者如果您使用它很多,请考虑将PropertyDescriptor存储在某处。

但是……就像乔恩一样,我真的不是百分之百地确定你要做什么!

我创建了一个哈希表来缓存reflection结果。 第一次,需要调用GetProperties并将结果存储到hastable中。 接下来,首先检查PropertyInfo对象列表的哈希表。 如果存在,请使用它。 如果没有,请调用GetProperties。

我用它来将datareader映射到实体列表。

我的实施是基于:尼克哈里森的.Net反思辩护 ( http://www.simple-talk.com/dotnet/.net-framework/a-defense-of-reflection-in-.net/ )。

所以,它是:

 public class MapeadorDataReaderListaObjetos { private Hashtable properties; private Hashtable Properties { get { if (properties == null) properties = new Hashtable(); return properties; } set { properties = value; } } private void LoadProperties(object targetObject, Type targetType) { var flags = BindingFlags.DeclaredOnly| BindingFlags.Instance| BindingFlags.Public; if (properties == null) { List propertyList = new List(); PropertyInfo[] objectProperties = targetType.GetProperties(flags); foreach (PropertyInfo currentProperty in objectProperties) { propertyList.Add(currentProperty); } properties = new Hashtable(); properties[targetType.FullName] = propertyList; } if (properties[targetType.FullName] == null) { List propertyList = new List(); PropertyInfo[] objectProperties = targetType.GetProperties(flags); foreach (PropertyInfo currentProperty in objectProperties) { propertyList.Add(currentProperty); } properties[targetType.FullName] = propertyList; } } public void MapearDataReaderListaObjetos  (IDataReader dr, List lista) where T: new() { Type businessEntityType = typeof(T); List entitys = new List(); T miObjeto = new T(); LoadProperties(miObjeto, businessEntityType); List sourcePoperties = Properties[businessEntityType.FullName] as List; while (dr.Read()) { T newObject = new T(); for (int index = 0; index < dr.FieldCount; index++) { for (int _indice = 0; _indice < sourcePoperties.Count; _indice++) { if (sourcePoperties[_indice].Name.ToUpper() == dr.GetName(index).ToUpper()); { string _tipoProp = sourcePoperties[_indice].PropertyType.ToString(); PropertyInfo info = sourcePoperties[_indice] as PropertyInfo; if ((info != null) && info.CanWrite) { info.SetValue(newObject, dr.GetValue(index), null); } } } } entitys.Add(newObject); } dr.Close(); lista = entitys; } } 

然后,我从我的DataAcces Layer中调用它,如下所示:

 public List  ListaxIdFactura (SqlTransaction Tr, Entities.ENFactura oBEFactura) { SqlConnection Cn = new SqlConnection(); Cn = _Connection.ConexionSEG(); List loBEFactura = new List(); using (Cn) { Cn.Open(); SqlDataReader drd = (odaSQL.fSelDrd(Cn, Tr, "Pa_CC_Factura_Listar_x_IdProveedor", oBEFactura)); if (drd != null) { if (drd.HasRows) { mapeador.MapearDataReaderListaObjetos (drd, loBEFactura); } } } return (loBEFactura); } 

因此,这样,DAL获取一个datareader,将其映射到业务实体列表,并将其返回到业务逻辑层。

这个类(MapeadorDataReaderListaObjetos)仍有一些问题,特别是在:

 info.SetValue(newObject, _valor, null); 

newObject和_valor必须是相同的类型,否则您将获得exception(从System.Int64到System.Int32的转换,以防您的实体属性为Int32,并且其数据库表中的相应字段为bigint)。

此外,如果实体属性是另一个实体,则这将不起作用,因为数据引用器不返回实体对象。

显然,这可以改进。

关于反思和代表,我发现这篇文章:反思 - 慢还是快? Abhishek Sur的解决方案示范, url为http://www.abhisheksur.com/2010/11/reflection-slow-or-faster-demonstration.html

另一篇好文章是:乔尔·波巴尔(Joel Pobar)在http://msdn.microsoft.com/en-us/magazine/cc163759.aspx上躲避制作快速应用程序的常见性能陷阱。

希望这可以帮助。

我认为最好的方法是获取getter或setter方法,将其转换为委托,并使用委托,没有更快的方法:

 PropertyInfo propertyInfoProperty1 = type.GetType().GetProperty("Property1"); Func get_Property1 = (Func)Delegate.CreateDelegate(typeof(Func), propertyInfoProperty1.GetGetMethod()); 

然后调用getter方法:

 string value = get_Property1(type); 

您可以缓存代理。

动态assembly应该有助于关注reflection性能。 有人在这里使用动态assembly实施了财产评估员。