我正在尝试从Linq表达式中检索object []。我使用方法名称和对象数组以将缓存键创建为字符串。最后,它将使我能够执行如下代码:
int id = 123;
DeleteCacheItems(()=> someInstance.GetCachedItem(id, null))
密钥将解析为“ NameSpaceOfSomeInstance.SomeInstance_123_null”
我的单元测试正常:
[TestMethod]
public void CacheDeleteViaExpressionTest()
{
int id = 3186718;
var something = ProviderFactory.Instance.Get(ProviderType.Something);
string methodName = CacheMethodManager.GetExpressionMethodFullName(() => something.GetRealtimeRooms(spid, null)); //returns ok
var objects = CacheMethodManager.GetExpressionArgumentValues(()=> something.GetRealtimeRooms(spid, null));
// returns object[0] = 3186718
// returns object[1] = null
string key = MethodCacheKey.GetCacheKey(methodName, objects, something);
Assert.IsTrue((int)objects[0] == id);
Assert.IsTrue(objects[1] == null);
}
现在我有一个尝试使用此代码的MVC控制器操作。我发现,如果表达式包含局部变量,则仅用值类型填充对象数组。
如果我在操作中使用参数中的 id ,则该参数无效。如果使用 localId,则可以使用。
我已经实现了此处描述的机制(Getting object array containing the values of parameters from a Lambda Expression)。 问题有点不同,因为我有一个递归调用来解析ConstantExpression。
[HttpPost]
public ActionResult ClearCache(int id)
{
try
{
CacheMethodManager manager = new CacheMethodManager();
var objects = CacheMethodManager.GetExpressionArgumentValues(()=> something.GetRealtimeRooms(**id**, null));
//here object[0] = "DisplayClass<> " // <---------------- This uses a closure class or something that wraps the value
int localId = id;
var objects2 = CacheMethodManager.GetExpressionArgumentValues(()=> something.GetRealtimeRooms(localId, null));
//here object2[0] = 3186718 // <---------------- WORKS
return Json(new { result = "OK!" });
}
catch (Exception e)
{
return Json(new { result = "Error", message = $"{e.Message}" });
}
}
public static object[] GetExpressionArgumentValues(Expression<Action> expr)
{
var call = (MethodCallExpression)expr.Body;
var args = call.Arguments;
object[] methodArguments = args.Select(c =>
c is ConstantExpression
? ((ConstantExpression)c).Value
: Extension.GetValue(Extension.ResolveMemberExpression(c))).ToArray();
return methodArguments;
}
public static MemberExpression ResolveMemberExpression(Expression expression)
{
if (expression is MemberExpression)
{
return (MemberExpression)expression;
}
else if (expression is ConstantExpression)
{
return (MemberExpression)expression;
}
else if (expression is UnaryExpression)
{
// if casting is involved, Expression is not x => x.FieldName but x => Convert(x.Fieldname)
return (MemberExpression)((UnaryExpression)expression).Operand;
}
else
{
throw new NotSupportedException(expression.ToString());
}
}
public static object GetValue(MemberExpression exp)
{
// expression is ConstantExpression or FieldExpression
if (exp.Expression is ConstantExpression)
{
var o = (((ConstantExpression)exp.Expression).Value)
.GetType()
.GetField(exp.Member.Name)
.GetValue(((ConstantExpression)exp.Expression).Value);
return o;
}
else if (exp.Expression is MemberExpression)
{
return GetValue((MemberExpression)exp.Expression);
}
else
{
throw new NotImplementedException();
}
}
为什么表达式的行为有所不同?我们如何在内部进行处理,以便开发人员无需创建局部变量?
谢谢 S