从linq表达式中检索对象列表

时间:2018-12-07 12:31:17

标签: c# linq

我正在尝试从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

0 个答案:

没有答案
相关问题