16

标题基本概括了所有内容。当我通过我的类进行一些反思时,MemberInfo.GetCustomAttributes() 方法是否会保留成员的属性顺序?官方文档并没有以任何方式说明任何事情。


如果你想知道我为什么需要这个,这里是完整的解释。现在提出的问题很长而且不需要,但也许有人可以为更大的问题想出一个替代解决方案,它不涉及依赖属性枚举顺序。

我正在尝试为(ASP.NET)应用程序创建一个灵活的框架,该应用程序预计具有相当长的生命周期。在整个过程中,它将获得许多必须从菜单中访问的表格。为了让开发人员的生活更轻松,我制作了一个MenuItemAttribute您可以将其应用于表单的类。此属性在其构造函数中具有无限数量的字符串参数,允许开发人员指定表单在菜单中的确切位置。一个典型的使用示例是这样的[MenuItem("Company", "Clients", "Orders")]这将意味着菜单应该有一个项目“公司”,在该项目下将有一个项目“客户”,在该项目下将有一个项目“订单” - 然后将打开表单。如果需要,单个表单可以具有多个这些属性 - 然后可以从菜单中的多个位置访问它。

显然,整个菜单是在运行时通过枚举我的程序集中的所有类并搜索该属性来构建的。但是最近我收到了一个请求,即菜单项应该以预定义的方式进行排序。具有相关功能的表单应在菜单中彼此相邻。请注意,这不是按字母排序,而是开发人员指定的预定义顺序。

这就带来了问题——如何在这些属性中指定顺序?由于MenuItemAttribute描述了整个层次结构,因此订单规范还应包括整个(或至少一部分)层次结构的订单号。仅针对较低层次结构的订单号是不够的。

我可以制作另一个属性 - MenuItemOrderHintAttribute,但是当有多个属性时,这会带来问题MenuItemAttribute。因此,原来的问题。

我还可以将 扩展MenuItemAttribute为采用两个数组或一对数组,但这会使语法复杂化很多。最后一个想法是我可以使字符串具有特殊格式,但恕我直言,那将是相当混乱的。


好的,我有另一个想法。让我们使用 Jon Skeet 建议的顺序。这将允许指定层次结构的最后一级的顺序,而不是更高的。但我可以修改该属性,使其不仅适用于类,还适用于程序集本身。在这种情况下,菜单项将没有关联的表单。在装配级别,这些属性可用于指定层次结构更高级别之间的排序。

这是集中式和分散式菜单系统之间的权衡。任何想法为什么这是一个坏主意?

4

4 回答 4

18

文件中元素的词法顺序绝对不能保证在生成的 CIL 程序集中以任何方式保持不变,也不能在反射返回的结果中得到尊重。在同一个应用程序域内的重复调用中,甚至不能保证这种排序是相同的!

请注意,MS 过去在反射的其他部分中破坏了这种顺序(注意到他们这样做实际上给他们的一些代码造成了一些问题),因此即使它目前恰好工作,也没有什么能阻止这种破坏将来或在不同的平台上。

考虑更改您的属性模型以允许直接表达语义信息,而不是依赖于排序。

于 2009-01-26T15:08:42.393 回答
8

我会在 MenuItemAttribute 构造函数中添加一个额外的(可选)值,即“订单”或“优先级”:

[MenuItem(0, "Company", "Clients", "Orders")]
[MenuItem(1, "Foo", "Bar", "Baz")]

我并不是说它会很漂亮,但它可以有效地让您指定排序。

于 2009-01-26T14:56:49.297 回答
1

不幸的是,不,您不能保证订单与您指定的订单相同。

编辑:一种解决方法

免责声明:如果我误解了您的最终问题,我提前道歉。

听起来好像您需要能够将n多个字符串传递给MenuItemAttributeMenuItemAttribute保持开发人员在属性构造函数中输入的这些字符串的顺序。

这是一个可能的解决方案:

使用MenuItemAttributeaLinkedList<String>来保持其状态。然后你可以在你的构造函数中迭代params String[]并将它们添加到LinkedList<String>将保持顺序的。

于 2009-01-26T14:50:31.633 回答
0

在我看来,您的问题实际上源于表单指定它们出现在菜单中的位置这一事实,这意味着您正在尝试通过组合程序集中的所有表单来构建菜单。如果您将菜单的结构与任何表单分开指定,并从与菜单项对应的类上定义的各种属性/属性解析表单,则可能会更容易。

例如

public class MenuItem
{
    string Text { get; }
    Type FormType { get; }
    ICollection<MenuItem> SubItems { get; }
}

然后选择菜单项时,以某种方式解析表单并显示它。这种方法的缺点是任何新表单都需要更改指定菜单结构的代码以及表单本身,但这将是非常小的......

于 2009-01-26T15:19:56.177 回答