C# 将匿名对象合并为单个匿名对象

C# 将匿名对象合并为单个匿名对象,c#,asp.net-mvc,C#,Asp.net Mvc,在某些情况下,我需要传递一些路由值组合,以创建特定路由的URL。而不是使用令人困惑的堆叠if案例,例如: (x != 0 && y != 0 ? (object)new { xId = 1, yId = 1 } : (x != 0 ? (object)new { xId = 1 } : (y != 0 ? (object)new { yId = 1 } : null))) 即2个值的4种可能组合(两种,一种或另一种,无) (如果你想知道为什么我需要if案例,这是针对一个有很多页

在某些情况下,我需要传递一些路由值组合,以创建特定路由的URL。而不是使用令人困惑的堆叠if案例,例如:

(x != 0 && y != 0 ? (object)new { xId = 1, yId = 1 } : (x != 0 ? (object)new { xId = 1 } : (y != 0 ? (object)new { yId = 1 } : null)))
即2个值的4种可能组合(两种,一种或另一种,无)

(如果你想知道为什么我需要if案例,这是针对一个有很多页面/链接的模板,但是根据它的使用方式,可以稍微不同地设置路由,而不是必须查找和更改每个链接,我希望能够根据路由的设置方式不同地应用路由值,如果我不这样做,它将添加useless查询字符串,用于不映射到管线值的值)

为了使其更易于阅读,最好有一个合并匿名类型的方法,例如:

Merge((x != 0 ? new { xId = 1 } : null), (y != 0 ? new { yId = 1 } : null))
我找到了这个解决方案,但我有一个问题,我想这要归结为我对这里要处理的问题的理解

以下是我对这种方法的一种变体:

public static dynamic Merge(params object[] objects)
{
    dynamic expando = new ExpandoObject();
    var merged = expando as IDictionary<string, object>;

    foreach (object obj in objects)
        if (obj != null)
            foreach (PropertyInfo property in obj.GetType().GetProperties())
                merged[property.Name] = property.GetValue(obj);

    return merged;
}
公共静态动态合并(参数对象[]对象)
{
动态expando=新的ExpandoObject();
var merged=expando作为IDictionary;
foreach(对象中的对象对象对象)
如果(obj!=null)
foreach(obj.GetType().GetProperties()中的PropertyInfo属性)
合并的[property.Name]=property.GetValue(obj);
返回合并;
}
当我传递此方法的输出时(路由值)除了发送给HtmlHelper的路由名称外,它还希望它使用指定的URL创建html链接,但由于找不到匹配的路由,因此无法执行此操作。它似乎无法访问合并对象中的路由值。方法返回类型是动态的,强制转换到对象或RouteValueDictionary没有任何区别

输出对象与普通匿名对象有什么不同?有没有办法使其能够访问合并对象内的键/值?

匿名对象(实际上,是一种编译时语法糖,以编译器指定的随机名称的常规类结尾)与
ExpandoObject
不同,后者是
dynamicbject
的实现

动态对象并不真正公开属性,但这些属性在运行时解析

我猜ASP.NET MVC使用反射检查那些匿名对象,而使用常规反射无法访问
ExpandoObject
中的属性。也就是说,路由应该实现特定的代码来处理路由参数,使用动态对象来处理您的用例

建议。。。
遗憾的是,我认为您需要保持当前的方法。有时我们需要一个神奇的解决方案,但如果在您的场景中效果良好,我会避免代码过于复杂。

在ASP.NET MVC中,HTML帮助程序如
Url.Action
HTML.ActionLink
也有重载,这需要
RouteValueDictionary
>。例如:

@{ var x = 1; var y = 1; }

@Html.ActionLink(
    "Go to contacts", "Contact", "Home",
    routeValues: 
        Merge(x != 0 ? new { xId = 1 } : null, y != 0 ? new { yId = 1 } : null),
    htmlAttributes: null))
使用此重载,可以通过以下方式实现
Merge
方法:

public static RouteValueDictionary Merge(params object[] routeValuesObjects)
{
    var result = new RouteValueDictionary();

    foreach (var routeValues in routeValuesObjects)
        foreach (var item in new RouteValueDictionary(routeValues))
            result[item.Key] = item.Value;

    return result;
}