比较两个 RouteValueDictionary 实例

发布于 2024-08-10 17:59:03 字数 1228 浏览 4 评论 0原文

我正在为我的应用程序编写一个帮助程序,它为给定的强类型控制器/操作写出一个菜单项,如下所示:

<%= Html.MenuLink<WhateverController>(c => c.WhateverAction(), "Whatever") %>

作为此过程的一部分,我想将 active 类应用到输出如果当前页面和链接到的页面相同,则链接。我认为最好的方法是将当前请求的 RouteValueDictionary 内容与提供给辅助方法的表达式结果的内容进行比较。但是,我无法找出比较两个 RouteValueDictionary 中的项目是否相同的好方法。

有没有一种简单的方法可以做到这一点?我实际上想通过以下方式完成它:

public static string MenuLink<T>(this HtmlHelper html, Expression<Action<T>> action, string linkText) where T : Controller
{
    // var link = html.ActionLink<T>(action, linkText, new {}); // Not important yet

    var routeValues = Microsoft.Web.Mvc.Internal.ExpressionHelper.GetRouteValuesFromExpression<T>(action);  // Might change?
    var currentRouteVals = html.ViewContext.RouteData.Values;
    bool isActivePage = /* are the contents of routeValues also 
                           inside currentRouteValues? */

    var tb = new TagBuilder("li");
    // Continues...
}

我尝试使用内置比较(==),但它似乎使用默认的相等实现,因此返回 false,因为它们不是同一个实例。我也尝试过以下方法:

bool isActivePage = routeValues.All(x => currentRouteVals.ContainsValue(x));

但这也不起作用。我完全是找错树了吗?

I am writing a helper for my application which writes out a menu item for a given strongly typed controller/action as follows:

<%= Html.MenuLink<WhateverController>(c => c.WhateverAction(), "Whatever") %>

As part of this process, I would like to apply the class of active to the outputted link if the current page and the page linked to are the same. I figure the best way of doing it is to compare the contents of the RouteValueDictionary for the current request to that of the result of the Expression given to the helper method. However, I cannot figure out a good way of comparing whether the items in the two RouteValueDictionarys are the same.

Is there a simple way of doing this? I effectively want to complete it in the following way:

public static string MenuLink<T>(this HtmlHelper html, Expression<Action<T>> action, string linkText) where T : Controller
{
    // var link = html.ActionLink<T>(action, linkText, new {}); // Not important yet

    var routeValues = Microsoft.Web.Mvc.Internal.ExpressionHelper.GetRouteValuesFromExpression<T>(action);  // Might change?
    var currentRouteVals = html.ViewContext.RouteData.Values;
    bool isActivePage = /* are the contents of routeValues also 
                           inside currentRouteValues? */

    var tb = new TagBuilder("li");
    // Continues...
}

I have tried using the built-in comparison (==), but it seems that it is using the default equality implementation and therefore returns false since they are not the same instance. I have also tried the following:

bool isActivePage = routeValues.All(x => currentRouteVals.ContainsValue(x));

but that doesn't work either. Am I completely barking up the wrong tree?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

掩耳倾听 2024-08-17 17:59:03

呸,我先提出问题,然后再找出答案。我在这里发帖以防其他人遇到这个问题。我需要的行如下:

bool isActivePage = routeValues.All(x => x.Value.ToString() == (currentRouteVals[x.Key].ToString()));

原来它最初是将它们作为对象进行比较,而不是作为字符串进行比较。将它们转换为字符串可以按照人们所希望的方式对它们进行比较,现在一切都很好。

需要注意的是,它们应该围绕这样的方式进行比较。如果以另一种方式比较它们,RouteValueDictionary 可能包含您关心的内容以外的内容(例如“id”值)。或者至少我现在是这么理解的。进一步的实验可能需要我重新审视这个......

Bah, I post the question and then figure out the answer. Am posting here in case anyone else faces this problem. The line I needed was as follows:

bool isActivePage = routeValues.All(x => x.Value.ToString() == (currentRouteVals[x.Key].ToString()));

Turns out it was originally comparing them as objects, not as strings. Converting them to strings compares them as one would hope, and now all is well.

It should be noted that they should be compared around this way. If they are compared round the other way, the RouteValueDictionary may contain things other than those you care about (such as an "id" value). Or at least that's how I understand it at the moment. Further experimentation may require me to revisit this...

┊风居住的梦幻卍 2024-08-17 17:59:03

我刚刚遇到了同样的问题,正在查看已接受的答案,并注意到它会:

  • 如果第二个routeValues列表中不存在密钥,则会导致异常,并且
  • 区分大小写,而Microsoft URI通常不是这种情况。
  • 如果密钥位于第二个列表中而不是第一个列表中,则列表将被比较为相同,这是不正确的。

该解决方案作为 RouteValueDictionary 的自包含扩展方法解决了上述问题:

public static bool AreEqual(this RouteValueDictionary rvdA, RouteValueDictionary rvdB)
{
    var Equal = 
        new Func<RouteValueDictionary, RouteValueDictionary, bool>((a, b) => a.All(kvp =>
       {
           object val = b[kvp.Key];
           return val != null && kvp.Value.ToString().Equals(val.ToString(), StringComparison.InvariantCultureIgnoreCase);
       }));                                                 

    return rvdA.Count == rvdB.Count && Equal(rvdA, rvdB) && Equal(rvdB, rvdA);
}   

I just encountered the same problem and was looking at the accepted answer and noticed it would:

  • cause an exception if the key didn't exist in the second routeValues list
  • is case sensitive which generally isn't the case for Microsoft URIs.
  • if the key is in the second list but not the first list the lists would compare as being the same which is incorrect.

This solution resolves the mentioned issues as a self contained extension method off of RouteValueDictionary:

public static bool AreEqual(this RouteValueDictionary rvdA, RouteValueDictionary rvdB)
{
    var Equal = 
        new Func<RouteValueDictionary, RouteValueDictionary, bool>((a, b) => a.All(kvp =>
       {
           object val = b[kvp.Key];
           return val != null && kvp.Value.ToString().Equals(val.ToString(), StringComparison.InvariantCultureIgnoreCase);
       }));                                                 

    return rvdA.Count == rvdB.Count && Equal(rvdA, rvdB) && Equal(rvdB, rvdA);
}   
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文