我已经通过逻辑从PropertyInfo实现了GetValue和Expression,但是我确信有更好的方法来完成我所做的每一件事。如果您对此代码有任何反馈意见,我将不胜感激,因为它确实按照规范工作:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
public class TestService
{
private static Dictionary ExpressionCache = new Dictionary();
public IEnumerable Execute(IEnumerable enums)
{
var expressionCache = (enums);
var props = typeof(T).GetProperties();
foreach (var e in enums)
{
foreach (var p in props)
{
var func = GetOrAddExpressionCache(p);
var value = string.Empty;
if (func == null)
{
Debug.WriteLine("Use Reflection");
value = p.GetValue(e).ToString();
}
else
{
Debug.WriteLine("Use Expression");
value = func(e);
}
yield return value;
}
}
}
private Func GetOrAddExpressionCache(PropertyInfo prop)
{
var key = prop.GetHashCode();
if (ExpressionCache.ContainsKey(key))
{
var func = ExpressionCache[key] as Func;
return func;
}else{
Task.Run(()=>AddExpressionCacheAsync(prop));
return null;
}
}
//Asynchronous nonblocking, which does not block a thread when adding a Cache
private async Task AddExpressionCacheAsync(PropertyInfo propertyInfo)
{
var key = propertyInfo.GetHashCode();
if (!ExpressionCache.ContainsKey(key))
{
var func = GetValueGetter(propertyInfo);
ExpressionCache.Add(key, func);
}
await Task.Yield();
}
private static Func GetValueGetter(PropertyInfo propertyInfo)
{
var instance = Expression.Parameter(propertyInfo.DeclaringType);
var property = Expression.Property(instance, propertyInfo);
var toString = Expression.Call(property, "ToString", Type.EmptyTypes);
return Expression.Lambda>(toString, instance).Compile();
}
}
class Program{
public static void Main(string[] args){
var data = new[] { new { Name = "Henry", Age = 25 } };
for (int i = 0; i < 2; i++)
{
var service = new TestService();
var result = service.Execute(data).ToArray();
}
}
}
/* Console :
Use Reflection
Use Reflection
Use Expression
Use Expression
*/
发布于 2019-01-23 11:05:33
null
值(NullReferenceException
)。TargetParameterCountException
)。prop.MetadataToken
与它们在(prop.Module.ModuleVersionId
)中声明的模块结合使用。Dictionary
中,它不是线程安全的.在最好的情况下,添加一个已经存在的键将引发异常。在最坏的情况下,字典的内部状态将被破坏。Execute
要采取一系列的项目,而不是单一的项目?扁平化结果很容易(data.SelectMany(service.Execute)
),“不平坦”不是--调用者必须计算出属性的数量,并且您必须编写一个方法将单个序列分割成子序列。ExpressionCache.ContainsKey(key)
(后面跟着ExpressionCache[key]
),而是使用TryGetValue
。这使您可以检查键的存在,并通过一次查找获得它的关联值。AddExpressionCacheAsync
async
没有任何意义。它没有做任何异步工作( await Task.Yield()
是无用的)。您已经从Task.Run
调用中调用了该方法,因此无论如何都会异步执行该方法。GetValueGetter
中,使用nameof(object.ToString)
而不是"ToString"
。Execute
-> GetPropertyValues
,enums
-> items
,func
-> compiledExpression
,GetValueGetter
-> CompileGetValueExpression
。e
-> item
,props
-> properties
,p
-> property
。https://codereview.stackexchange.com/questions/211976
复制相似问题